跳到内容

订阅我们的新闻通讯以获取更新和技巧

Parea 用于观察、测试和微调 Instructor

Parea 是一个帮助团队监控、协作、测试和标注 LLM 应用的平台。在这篇博文中,我们将探讨如何使用 Parea 来增强 OpenAI 客户端,并调试 + 改进 instructor 调用。Parea 有一些特性使其对 instructor 尤其有用

  • 它会自动将因重试导致的 LLM 调用分组到单个跟踪下
  • 它会自动跟踪使用 instructor 时发生的任何验证错误计数和字段
  • 它提供了一个 UI,可以通过填写表单而不是编辑 JSON 对象来标注 JSON 响应
配置 Parea

在开始本教程之前,请确保您已注册 Parea 账户。您还需要创建一个 API 密钥

示例:使用 Instructor 文档中的 URL 编写电子邮件

我们将通过使用 instructor 编写仅包含来自 instructor 文档中 URL 的电子邮件来演示 Parea。在继续之前,您需要安装我们的依赖项,只需运行以下命令即可。

使用 Instructor 分析 Youtube 字幕

提取章节信息

代码片段

一如既往,代码已在我们的仓库中 examples/youtube 文件夹下的 run.py 文件中提供,供您参考。

在这篇文章中,我们将向您展示如何使用 instructor 将 Youtube 视频转录总结成不同的章节,然后探讨一些如何将代码适应不同应用的方法。

阅读完本文,您将能够根据下面的视频构建一个应用程序。

为什么 Instructor 是从 LLM 获取 JSON 的最佳方式

像 GPT 这样的大型语言模型 (LLMs) 功能强大,但让它们返回格式良好的 JSON 可能具有挑战性。这就是 Instructor 库的亮点所在。Instructor 允许您使用 Python 类型注释和 Pydantic 模型轻松地将 LLM 输出映射到 JSON 数据。

Instructor 使从 GPT-3.5、GPT-4、GPT-4-Vision 等 LLM 以及包括 Mistral/MixtralOllamallama-cpp-python 在内的开源模型获取结构化数据(如 JSON)变得容易。

它基于 Pydantic 构建,以其简单性、透明性和以用户为中心的设计而脱颖而出。Instructor 帮助您管理验证上下文、使用Tenacity 进行重试以及流式处理列表部分响应。

使用 Instructor 通过时间过滤器增强 RAG

检索增强生成 (RAG) 系统通常需要处理具有基于时间约束的查询,例如“上个季度发布了哪些新功能?”或“显示过去一周的支持工单。” 有效的时间过滤对于提供准确、相关的响应至关重要。

Instructor 是一个 Python 库,它简化了将大型语言模型 (LLMs) 与数据源和 API 集成的过程。它允许使用 Pydantic 定义结构化输出模型,这些模型可用作提示或解析 LLM 输出。

为什么 Logfire 非常适合 FastAPI + Instructor

Logfire 是一个新工具,它通过 Open Telemetry 为您的应用程序提供关键洞察。Logfire 不会使用临时的打印语句,而是帮助分析应用程序的每个部分,并直接集成到 Pydantic 和 FastAPI 这两个在 Instructor 用户中流行的库中。

简而言之,这是帮助您的应用程序到达终点并超越的秘诀。我们将通过两个示例向您展示如何轻松地将 Logfire 集成到 FastAPI 中,这是 Instructor 用户中最受欢迎的选择之一

  1. 从单个用户查询中提取数据
  2. 使用 asyncio 并行处理多个用户
  3. 使用 Iterable 流式传输多个对象,以便按需获取

Logfire

简介

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

我们将介绍以下示例

  1. 使用 Instructor 分类诈骗邮件
  2. 使用 llm_validator 执行简单验证
  3. 使用 GPT4V 从信息图表中提取数据到 markdown 表格

基于字符串初始化的统一提供商接口

Instructor 现在提供了一种简化的方式,可以使用一个统一的接口初始化任何支持的 LLM 提供商。这种方法使得在不同 LLM 提供商之间切换比以往任何时候都更容易,同时保持您所依赖的结构化输出功能。

问题

随着 LLM 提供商数量的增长,初始化和使用不同客户端库的复杂性也随之增加。每个提供商都有自己的初始化模式、API 结构和特性。这导致代码在提供商之间不可移植,并且在您想尝试新模型时需要进行大量重构。

解决方案:基于字符串的初始化

我们引入了一个新的统一接口,允许您使用简单的字符串格式初始化任何受支持的提供商

import instructor
from pydantic import BaseModel

class UserInfo(BaseModel):
    name: str
    age: int

# Initialize any provider with a single consistent interface
client = instructor.from_provider("openai/gpt-4")
client = instructor.from_provider("anthropic/claude-3-sonnet")
client = instructor.from_provider("google/gemini-pro")
client = instructor.from_provider("mistral/mistral-large")

from_provider 函数接受 "provider/model-name" 格式的字符串,并处理使用正确的模型设置相应客户端的所有细节。这提供了几个关键优势

  • 简化初始化:无需手动创建特定于提供商的客户端
  • 统一接口:相同的语法适用于所有提供商
  • 减少依赖暴露:您无需在应用程序代码中导入特定的提供商库
  • 轻松实验:只需更改一行代码即可在提供商之间切换

支持的提供商

基于字符串的初始化目前支持生态系统中的所有主要提供商

  • OpenAI: "openai/gpt-4", "openai/gpt-4o", "openai/gpt-3.5-turbo"
  • Anthropic: "anthropic/claude-3-opus-20240229", "anthropic/claude-3-sonnet-20240229", "anthropic/claude-3-haiku-20240307"
  • Google Gemini: "google/gemini-pro", "google/gemini-pro-vision"
  • Mistral: "mistral/mistral-small-latest", "mistral/mistral-medium-latest", "mistral/mistral-large-latest"
  • Cohere: "cohere/command", "cohere/command-r", "cohere/command-light"
  • Perplexity: "perplexity/sonar-small-online", "perplexity/sonar-medium-online"
  • Groq: "groq/llama2-70b-4096", "groq/mixtral-8x7b-32768", "groq/gemma-7b-it"
  • Writer: "writer/palmyra-instruct", "writer/palmyra-instruct-v2"
  • AWS Bedrock: "bedrock/anthropic.claude-v2", "bedrock/amazon.titan-text-express-v1"
  • Cerebras: "cerebras/cerebras-gpt", "cerebras/cerebras-gpt-2.7b"
  • Fireworks: "fireworks/llama-v2-70b", "fireworks/firellama-13b"
  • Vertex AI: "vertexai/gemini-pro", "vertexai/text-bison"
  • Google GenAI: "genai/gemini-pro", "genai/gemini-pro-vision"

每个提供商将使用合理的默认值进行初始化,但您也可以传递额外的关键字参数来自定义配置。有关模型特定细节,请查阅各提供商的文档。

异步支持

统一接口完全支持同步和异步客户端

# Synchronous client (default)
client = instructor.from_provider("openai/gpt-4")

# Asynchronous client
async_client = instructor.from_provider("anthropic/claude-3-sonnet", async_client=True)

# Use like any other async client
response = await async_client.chat.completions.create(
    response_model=UserInfo,
    messages=[{"role": "user", "content": "Extract information about John who is 30 years old"}]
)

模式选择

您还可以指定与提供商一起使用的结构化输出模式

import instructor
from instructor import Mode

# Override the default mode for a provider
client = instructor.from_provider(
    "anthropic/claude-3-sonnet", 
    mode=Mode.ANTHROPIC_TOOLS
)

# Use JSON mode instead of the default tools mode
client = instructor.from_provider(
    "mistral/mistral-large", 
    mode=Mode.MISTRAL_STRUCTURED_OUTPUTS
)

# Use reasoning tools instead of regular tools for Anthropic
client = instructor.from_provider(
    "anthropic/claude-3-opus", 
    mode=Mode.ANTHROPIC_REASONING_TOOLS
)

如果未指定,每个提供商将使用其推荐的默认模式

  • OpenAI: Mode.OPENAI_FUNCTIONS
  • Anthropic: Mode.ANTHROPIC_TOOLS
  • Google Gemini: Mode.GEMINI_JSON
  • Mistral: Mode.MISTRAL_TOOLS
  • Cohere: Mode.COHERE_TOOLS
  • Perplexity: Mode.JSON
  • Groq: Mode.GROQ_TOOLS
  • Writer: Mode.WRITER_JSON
  • Bedrock: Mode.ANTHROPIC_TOOLS (适用于 Bedrock 上的 Claude)
  • Vertex AI: Mode.VERTEXAI_TOOLS

您可以根据您的特定需求和模型功能随时自定义此设置。

错误处理

from_provider 函数包含健壮的错误处理,帮助您快速识别和解决问题

# Missing dependency
try:
    client = instructor.from_provider("anthropic/claude-3-sonnet")
except ImportError as e:
    print("Error: Install the anthropic package first")
    # pip install anthropic

# Invalid provider format
try:
    client = instructor.from_provider("invalid-format")
except ValueError as e:
    print(e)  # Model string must be in format "provider/model-name"

# Unsupported provider
try:
    client = instructor.from_provider("unknown/model")
except ValueError as e:
    print(e)  # Unsupported provider: unknown. Supported providers are: ...

该函数验证提供商字符串格式,检查提供商是否受支持,并确保安装了必要的软件包。

环境变量

与原生客户端库一样,from_provider 遵循为每个提供商设置的环境变量

# Set environment variables 
import os
os.environ["OPENAI_API_KEY"] = "your-openai-key"
os.environ["ANTHROPIC_API_KEY"] = "your-anthropic-key" 
os.environ["MISTRAL_API_KEY"] = "your-mistral-key"

# No need to pass API keys directly
client = instructor.from_provider("openai/gpt-4")

故障排除

以下是使用统一提供商接口时的一些常见问题和解决方案

未找到模型错误

如果您收到 404 错误,请检查您是否使用了正确的模型名称格式

Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-3-haiku'}}

对于 Anthropic 模型,始终包含版本日期:- ✅ 正确:anthropic/claude-3-haiku-20240307 - ❌ 错误:anthropic/claude-3-haiku

特定于提供商的参数

某些提供商的 API 调用需要特定参数

# Anthropic requires max_tokens
anthropic_client = instructor.from_provider(
    "anthropic/claude-3-haiku-20240307", 
    max_tokens=400  # Required for Anthropic
)

# Use models with vision capabilities for multimodal content
gemini_client = instructor.from_provider(
    "google/gemini-pro-vision"  # Required for image processing
)

工作示例

这是一个完整的示例,演示了使用多个提供商的 automodel 功能

import os
import asyncio
import instructor
from pydantic import BaseModel, Field

class UserInfo(BaseModel):
    """User information extraction model."""
    name: str = Field(description="The user's full name")
    age: int = Field(description="The user's age in years")
    occupation: str = Field(description="The user's job or profession")

async def main():
    # Test OpenAI
    openai_client = instructor.from_provider("openai/gpt-3.5-turbo")
    openai_result = openai_client.chat.completions.create(
        response_model=UserInfo,
        messages=[{"role": "user", "content": "Jane Doe is a 28-year-old data scientist."}]
    )
    print(f"OpenAI result: {openai_result.model_dump()}")

    # Test Anthropic with async client
    if os.environ.get("ANTHROPIC_API_KEY"):
        anthropic_client = instructor.from_provider(
            model="anthropic/claude-3-haiku-20240307",
            async_client=True,
            max_tokens=400  # Required for Anthropic
        )
        anthropic_result = await anthropic_client.chat.completions.create(
            response_model=UserInfo,
            messages=[{"role": "user", "content": "John Smith is a 35-year-old software engineer."}]
        )
        print(f"Anthropic result: {anthropic_result.model_dump()}")

if __name__ == "__main__":
    asyncio.run(main())

结论

基于字符串的初始化是使 Instructor 更加用户友好和灵活的重要一步。它降低了使用多个提供商的学习曲线,并使得尝试不同模型比以往任何时候都更容易。

优点包括:- 统一接口简化初始化 - 自动选择合适的默认模式 - 支持同步和异步客户端 - 清晰的错误消息,快速识别问题 - 遵循特定于提供商的环境变量 - 涵盖整个 LLM 生态系统的全面模型选择

无论您是构建新应用程序还是迁移现有应用程序,统一提供商接口都提供了一种更清晰、更易于维护的方式来处理整个 LLM 生态系统中的结构化输出。

立即使用 instructor.from_provider() 尝试吧,并在我们的仓库中查看完整示例代码

宣布 instructor=1.0.0

在过去 10 个月里,我们秉持“易于尝试,易于删除”的原则构建了 instructor。我们通过使用 instructor 包修补 openai 客户端,并添加了 response_modelmax_retriesvalidation_context 等新参数来实现这一点。因此,我坚信 instructor 是从 LLM API 获取结构化数据的最佳方式

但因此,我们在使类型提示良好工作的同时为您提供更多开发时控制方面遇到了一些困难。我很高兴推出 1.0.0 版本,它在类型提示方面清理了 API,而不会牺牲易用性。

多语言摘要任务中的语言匹配

当要求语言模型总结文本时,存在生成摘要最终为英文的风险,即使源文本是另一种语言。这可能是因为指令是以英文提供的,使模型偏向英文输出。

在这篇文章中,我们探索了一些技术来确保生成的摘要语言与源文本语言一致。我们利用 Pydantic 进行数据验证,并使用 langdetect 库进行语言识别。

使用 Anthropic 获取结构化输出

特别鸣谢 Shreya 对 anthropic 支持的贡献。截至目前,除流式传输支持外,所有功能均可正常使用。

对于那些渴望尝试的人,只需使用 ANTHROPIC_JSON 修补客户端,这将使您能够利用 anthropic 客户端进行请求。

pip install instructor[anthropic]

缺失的功能

我们承认我们知道目前缺少部分流式传输以及针对 XML 的更好重试支持。我们正在努力开发,很快就会推出。

from pydantic import BaseModel
from typing import List
import anthropic
import instructor

# Patching the Anthropics client with the instructor for enhanced capabilities
anthropic_client = instructor.from_openai(
    create=anthropic.Anthropic().messages.create,
    mode=instructor.Mode.ANTHROPIC_JSON
)

class Properties(BaseModel):
    name: str
    value: str

class User(BaseModel):
    name: str
    age: int
    properties: List[Properties]

user_response = anthropic_client(
    model="claude-3-haiku-20240307",
    max_tokens=1024,
    max_retries=0,
    messages=[
        {
            "role": "user",
            "content": "Create a user for a model with a name, age, and properties.",
        }
    ],
    response_model=User,
)  # type: ignore

print(user_response.model_dump_json(indent=2))
"""
{
    "name": "John",
    "age": 25,
    "properties": [
        {
            "key": "favorite_color",
            "value": "blue"
        }
    ]
}

我们在处理深度嵌套类型时遇到了挑战,并热切邀请社区进行测试、提供反馈并提出必要的改进建议,以便我们增强对 anthropic 客户端的支持。