在 Instructor 中使用联合类型¶
本指南解释了如何在 Instructor 中使用联合类型,它允许您处理语言模型可能产生的多种响应类型。当您需要 LLM 在不同的响应格式或动作类型之间进行选择时,联合类型特别有用。
Union vs. union
原始 union.md
页面中的内容已整合到此更全面的指南中。该页面展示了一个使用联合类型处理多种动作类型的基本示例。
基本联合类型¶
联合类型允许您指定字段可以是几种类型之一
from typing import Union
from pydantic import BaseModel
class Response(BaseModel):
value: Union[str, int] # Can be either string or integer
判别联合类型¶
使用判别联合类型处理不同的响应类型
from typing import Literal, Union
from pydantic import BaseModel
import instructor
from openai import OpenAI
class UserQuery(BaseModel):
type: Literal["user"]
username: str
class SystemQuery(BaseModel):
type: Literal["system"]
command: str
Query = Union[UserQuery, SystemQuery]
# Usage with Instructor
client = instructor.from_openai(OpenAI())
response = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Query,
messages=[{"role": "user", "content": "Parse: user lookup jsmith"}],
)
可选字段¶
将 Union 与 Optional 结合使用来处理可空字段
from typing import Optional
from pydantic import BaseModel
class User(BaseModel):
name: str
email: Optional[str] = None # Same as Union[str, None]
最佳实践¶
- 类型提示:使用适当的类型提示来提高清晰度并改善 IDE 支持
- 判别字段:为复杂的联合类型添加判别字段(如
type
),以帮助 LLM 正确选择 - 验证:为联合字段添加验证器,以确保数据有效
- 文档:在模型中使用文档字符串清晰地记录预期的类型
- 字段名称:使用描述性字段名称来引导模型的输出
- 示例:在您的 Pydantic 模型中包含示例,以帮助 LLM 理解预期的格式
常见模式¶
多种响应类型¶
from typing import Union, Literal
from pydantic import BaseModel
class SuccessResponse(BaseModel):
status: Literal["success"]
data: dict
class ErrorResponse(BaseModel):
status: Literal["error"]
message: str
Response = Union[SuccessResponse, ErrorResponse]
嵌套联合类型¶
from typing import Union, List
from pydantic import BaseModel
class TextContent(BaseModel):
type: Literal["text"]
text: str
class ImageContent(BaseModel):
type: Literal["image"]
url: str
class Message(BaseModel):
content: List[Union[TextContent, ImageContent]]
使用联合类型进行动态动作选择¶
您可以使用联合类型编写“代理”,这些代理通过选择一个输出类来动态选择动作。例如,在一个搜索和查找函数中
from pydantic import BaseModel
from typing import Union
class Search(BaseModel):
query: str
def execute(self):
# Implementation for search
return f"Searching for: {self.query}"
class Lookup(BaseModel):
key: str
def execute(self):
# Implementation for lookup
return f"Looking up key: {self.key}"
class Action(BaseModel):
action: Union[Search, Lookup]
def execute(self):
return self.action.execute()
通过这种模式,LLM 可以根据用户的输入决定是执行搜索还是查找。
import instructor
from openai import OpenAI
client = instructor.from_openai(OpenAI())
# Let the LLM decide what action to take
result = client.chat.completions.create(
model="gpt-4",
response_model=Action,
messages=[
{
"role": "system",
"content": "You're an assistant that helps search or lookup information.",
},
{"role": "user", "content": "Find information about climate change"},
],
)
# Execute the chosen action
print(result.execute()) # Likely outputs: "Searching for: climate change"
与 Instructor 集成¶
使用联合类型进行验证¶
from instructor import patch
from openai import OpenAI
client = patch(OpenAI())
def validate_response(response: Response) -> bool:
if isinstance(response, ErrorResponse):
return len(response.message) > 0
return True
result = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Response,
validation_hook=validate_response,
messages=[{"role": "user", "content": "Process this request"}],
)
使用联合类型进行流式处理¶
def stream_content():
response = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Message,
stream=True,
messages=[{"role": "user", "content": "Generate mixed content"}],
)
for partial in response:
if partial.content:
for item in partial.content:
if isinstance(item, TextContent):
print(f"Text: {item.text}")
elif isinstance(item, ImageContent):
print(f"Image: {item.url}")
错误处理¶
处理联合类型验证错误
from pydantic import ValidationError
try:
response = Response(status="invalid", data={"key": "value"}) # Invalid status
except ValidationError as e:
print(f"Validation error: {e}")
类型检查¶
使用 isinstance() 进行运行时类型检查
def process_response(response: Response):
if isinstance(response, SuccessResponse):
# Handle success case
process_data(response.data)
elif isinstance(response, ErrorResponse):
# Handle error case
log_error(response.message)
有关联合类型的更多信息,请查阅 Pydantic 文档中关于联合类型的部分。
```from typing import Literal, Union from pydantic import BaseModel import instructor from openai import OpenAI
class Action(BaseModel): """基础动作类。"""
type: str
class SendMessage(BaseModel): type: Literal["send_message"] message: str recipient: str
class MakePayment(BaseModel): type: Literal["make_payment"] amount: float recipient: str
Action = Union[SendMessage, MakePayment]
在 Instructor 中的使用¶
client = instructor.patch(OpenAI()) response = client.chat.completions.create( model="gpt-3.5-turbo", response_model=Action, messages=[{"role": "user", "content": "Send a payment of $50 to John."}], ) ], )
```from typing import Literal, Union
from pydantic import BaseModel
import instructor
from openai import OpenAI
class SearchAction(BaseModel):
type: Literal["search"]
query: str
class EmailAction(BaseModel):
type: Literal["email"]
to: str
subject: str
body: str
Action = Union[SearchAction, EmailAction]
# The model can choose which action to take
client = instructor.patch(OpenAI())
response = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Action,
messages=[{"role": "user", "content": "Find me information about climate change."}],
)
],
)
```from typing import Literal, Union from pydantic import BaseModel import instructor from openai import OpenAI
class TextResponse(BaseModel): type: Literal["text"] content: str
class ImageResponse(BaseModel): type: Literal["image"] url: str caption: str
Response = Union[TextResponse, ImageResponse]
已修补的客户端¶
client = instructor.patch(OpenAI()) response = client.chat.completions.create( model="gpt-3.5-turbo", response_model=Response, messages=[{"role": "user", "content": "Tell me a joke about programming."}], ) ], )
```from typing import Union
from pydantic import BaseModel
class Response(BaseModel):
"""A more complex example showing nested Union fields."""
result: Union[str, int, float, bool]
bool]
```from typing import Dict, List, Union, Any from pydantic import BaseModel
class Response(BaseModel): """一个更复杂的示例,展示了嵌套的 Union 字段。"""
data: Dict[str, Union[str, int, List[Any]]]
Any]]] ```