提示工程通用技巧¶
使用 Instructor 和 Pydantic 进行函数调用的核心主题是使模型尽可能地具有自描述性、模块化和灵活性,同时保持数据的完整性和易用性。
- 模块化:设计自包含的组件以便重用。
- 自描述:使用 Pydantic 的
Field
来提供清晰的字段描述。 - 可选性:对可空字段使用 Python 的
Optional
类型并设置合理的默认值。 - 标准化:对具有固定值集合的字段使用枚举;包含一个备用选项。
- 动态数据:对任意属性使用键值对,并限制列表长度。
- 实体关系:定义明确的标识符和关系字段。
- 上下文逻辑:可选地在可重用组件中添加一个“思维链”字段,以提供额外上下文。
模块化思维链¶
这种“思维链”方法提高了数据质量,但可以使用模块化组件而非全局 CoT。
from pydantic import BaseModel, Field
class Role(BaseModel):
chain_of_thought: str = Field(
..., description="Think step by step to determine the correct title"
)
title: str
class UserDetail(BaseModel):
age: int
name: str
role: Role
利用可选属性¶
使用 Python 的 Optional 类型并设置默认值,以防止出现空字符串等不需要的默认值。
from typing import Optional
from pydantic import BaseModel, Field
class UserDetail(BaseModel):
age: int
name: str
role: Optional[str] = Field(default=None)
处理函数调用中的错误¶
您可以创建一个包装类来保存操作结果或错误消息。这使您即使发生错误也能留在函数调用中,从而在不中断代码流的情况下更好地处理错误。
from pydantic import BaseModel, Field
from typing import Optional
class UserDetail(BaseModel):
age: int
name: str
role: Optional[str] = Field(default=None)
class MaybeUser(BaseModel):
result: Optional[UserDetail] = Field(default=None)
error: bool = Field(default=False)
message: Optional[str]
def __bool__(self):
return self.result is not None
使用 MaybeUser
类,您可以在 result 中接收 UserDetail
对象,或在 message 中获取错误消息。
使用 Maybe 模式进行简化¶
您可以使用 instructor 从任何 BaseModel
动态创建 Maybe
模式,从而进一步简化此过程。
import instructor
from pydantic import BaseModel
class UserDetail(BaseModel):
age: int
name: str
MaybeUser = instructor.Maybe(UserDetail)
这使您可以快速为任何类创建 Maybe 类型,简化了流程。
枚举技巧¶
为了防止数据错位,对标准化字段使用 Enums。始终包含一个“其他”选项作为备用,以便模型可以指示不确定性。
from enum import Enum, auto
from pydantic import BaseModel, Field
class Role(Enum):
PRINCIPAL = auto()
TEACHER = auto()
STUDENT = auto()
OTHER = auto()
class UserDetail(BaseModel):
age: int
name: str
role: Role = Field(
description="Correctly assign one of the predefined roles to the user."
)
字面量¶
如果您在使用 Enum
时遇到困难,可以使用 Literal
作为替代方案。
from typing import Literal
from pydantic import BaseModel
class UserDetail(BaseModel):
age: int
name: str
role: Literal["PRINCIPAL", "TEACHER", "STUDENT", "OTHER"]
如果您想进一步提高性能,可以在字段描述或文档字符串中重申要求。
重申长指令¶
对于复杂的属性,在字段描述中重申指令会有所帮助。
from pydantic import BaseModel, Field
class Role(BaseModel):
"""
Extract the role based on the following rules ...
"""
instructions: str = Field(
...,
description="Restate the instructions and rules to correctly determine the title.",
)
title: str
class UserDetail(BaseModel):
age: int
name: str
role: Role
处理任意属性¶
当您需要提取未定义的属性时,请使用键值对列表。
from typing import List
from pydantic import BaseModel, Field
class Property(BaseModel):
key: str
value: str
class UserDetail(BaseModel):
age: int
name: str
properties: List[Property] = Field(
..., description="Extract any other properties that might be relevant."
)
限制列表长度¶
处理属性列表,特别是任意属性时,管理长度至关重要。您可以使用提示和枚举来限制列表长度,从而确保属性集可管理。
from typing import List
from pydantic import BaseModel, Field
class Property(BaseModel):
index: str = Field(..., description="Monotonically increasing ID")
key: str
value: str
class UserDetail(BaseModel):
age: int
name: str
properties: List[Property] = Field(
...,
description="Numbered list of arbitrary extracted properties, should be less than 6",
)
对简单类型使用元组
对于简单类型,元组是自定义类的更紧凑替代方案,尤其是在属性不需要额外描述时。
from typing import List, Tuple
from pydantic import BaseModel, Field
class UserDetail(BaseModel):
age: int
name: str
properties: List[Tuple[int, str]] = Field(
...,
description="Numbered list of arbitrary extracted properties, should be less than 6",
)
高级任意属性¶
对于多个用户,在提取属性时尽量使用一致的键名。
from typing import List
from pydantic import BaseModel
class UserDetail(BaseModel):
id: int
age: int
name: str
class UserDetails(BaseModel):
"""
Extract information for multiple users.
Use consistent key names for properties across users.
"""
users: List[UserDetail]
这份改进的指南应为 Python 中的结构工程提供更清晰、更有条理的方法。
定义实体间的关系¶
在实体间存在关系的情况下,在模型中明确定义这些关系至关重要。以下示例演示了如何通过包含 id 和 friends 字段来定义用户之间的关系。
from typing import List
from pydantic import BaseModel, Field
class UserDetail(BaseModel):
id: int = Field(..., description="Unique identifier for each user.")
age: int
name: str
friends: List[int] = Field(
...,
description="Correct and complete list of friend IDs, representing relationships between users.",
)
class UserRelationships(BaseModel):
users: List[UserDetail] = Field(
...,
description="Collection of users, correctly capturing the relationships among them.",
)
在不同上下文重用组件¶
您可以在模型内的不同上下文重用同一个组件。在此示例中,TimeRange 组件用于 work_time 和 leisure_time。
from pydantic import BaseModel, Field
class TimeRange(BaseModel):
start_time: int = Field(..., description="The start time in hours.")
end_time: int = Field(..., description="The end time in hours.")
class UserDetail(BaseModel):
id: int = Field(..., description="Unique identifier for each user.")
age: int
name: str
work_time: TimeRange = Field(
..., description="Time range during which the user is working."
)
leisure_time: TimeRange = Field(
..., description="Time range reserved for leisure activities."
)
有时,像 TimeRange 这样的组件可能需要一些上下文或额外的逻辑才能有效使用。在组件内使用“思维链”字段有助于理解或优化时间范围分配。
from pydantic import BaseModel, Field
class TimeRange(BaseModel):
chain_of_thought: str = Field(
..., description="Step by step reasoning to get the correct time range"
)
start_time: int = Field(..., description="The start time in hours.")
end_time: int = Field(..., description="The end time in hours.")