关于提示的通用技巧¶
在我们深入探讨模式工程的一些重大应用之前,我想为你提供成功的工具。这个笔记本旨在分享一些使用提示以充分利用模型的一般建议。
在你可能认为提示工程就像在记事本中编码一样,需要大量调整这堵文本墙。但通过模式工程,你可以用更少的工作从提示中获得更多的效果。
分类¶
对于分类问题,我们通常发现有两种建模方法。
- 使用枚举
- 使用文字常量
在Python中使用枚举,当你需要一组相关的命名常量,并且你希望确保类型安全、可读性以及防止无效值时。枚举对于分组和遍历这些常量非常有帮助。
当你有一小组不变的值,不需要分组或迭代,并且类型安全和防止无效值不太重要时,使用字面量。对于基本的、一次性的值,字面量更简单直接。
在 [1]:
Copied!
import instructor
from openai import OpenAI
from enum import Enum
from pydantic import BaseModel, Field
from typing_extensions import Literal
client = instructor.patch(OpenAI())
# Tip: Do not use auto() as they cast to 1,2,3,4
class House(Enum):
Gryffindor = "gryffindor"
Hufflepuff = "hufflepuff"
Ravenclaw = "ravenclaw"
Slytherin = "slytherin"
class Character(BaseModel):
age: int
name: str
house: House
def say_hello(self):
print(
f"Hello, I'm {self.name}, I'm {self.age} years old and I'm from {self.house.value.title()}"
)
resp = client.chat.completions.create(
model="gpt-4-1106-preview",
messages=[{"role": "user", "content": "Harry Potter"}],
response_model=Character,
)
resp.model_dump()
import instructor from openai import OpenAI from enum import Enum from pydantic import BaseModel, Field from typing_extensions import Literal client = instructor.patch(OpenAI()) # 提示:不要使用 auto(),因为它们会转换为 1,2,3,4 class House(Enum): Gryffindor = "gryffindor" Hufflepuff = "hufflepuff" Ravenclaw = "ravenclaw" Slytherin = "slytherin" class Character(BaseModel): age: int name: str house: House def say_hello(self): print( f"你好,我是 {self.name},我 {self.age} 岁,我来自 {self.house.value.title()}" ) resp = client.chat.completions.create( model="gpt-4-1106-preview", messages=[{"role": "user", "content": "Harry Potter"}], response_model=Character, ) resp.model_dump()
输出[1] :
{'age': 17, 'name': 'Harry Potter', 'house': <House.Gryffindor: 'gryffindor'>} 在 [2]:
Copied!
resp.say_hello()
resp.say_hello()
Hello, I'm Harry Potter, I'm 17 years old and I'm from Gryffindor
在 [3]:
Copied!
class Character(BaseModel):
age: int
name: str
house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]
resp = client.chat.completions.create(
model="gpt-4-1106-preview",
messages=[{"role": "user", "content": "Harry Potter"}],
response_model=Character,
)
resp.model_dump()
class Character(BaseModel): age: int name: str house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] resp = client.chat.completions.create( model="gpt-4-1106-preview", messages=[{"role": "user", "content": "哈利·波特"}], response_model=Character, ) resp.model_dump()
输出[3]:
{'age': 11, 'name': 'Harry Potter', 'house': 'Gryffindor'} 任意属性¶
很多时候,有一些长的属性你可能想从数据中提取,而这些属性我们无法预先指定。我们可以通过定义一个任意的键值存储来解决这个问题,如下所示:
在 [4]:
Copied!
class Property(BaseModel):
key: str = Field(description="Must be snake case")
value: str
class Character(BaseModel):
age: int
name: str
house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]
properties: list[Property]
resp = client.chat.completions.create(
model="gpt-4-1106-preview",
messages=[{"role": "user", "content": "Snape from Harry Potter"}],
response_model=Character,
)
resp.model_dump()
class Property(BaseModel): key: str = Field(description="必须是蛇形命名") value: str class Character(BaseModel): age: int name: str house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] properties: list[Property] resp = client.chat.completions.create( model="gpt-4-1106-preview", messages=[{"role": "user", "content": "Snape from Harry Potter"}], response_model=Character, ) resp.model_dump()
输出[4]:
{'age': 38,
'name': 'Severus Snape',
'house': 'Slytherin',
'properties': [{'key': 'role', 'value': 'Potions Master'},
{'key': 'patronus', 'value': 'Doe'},
{'key': 'loyalty', 'value': 'Dumbledore'},
{'key': 'played_by', 'value': 'Alan Rickman'}]} 在 [5]:
Copied!
class Property(BaseModel):
index: str = Field(..., description="Monotonically increasing ID")
key: str = Field(description="Must be snake case")
value: str
class Character(BaseModel):
age: int
name: str
house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]
properties: list[Property] = Field(
...,
description="Numbered list of arbitrary extracted properties, should be exactly 5",
)
resp = client.chat.completions.create(
model="gpt-4-1106-preview",
messages=[{"role": "user", "content": "Snape from Harry Potter"}],
response_model=Character,
)
resp.model_dump()
class Property(BaseModel): index: str = Field(..., description="单调递增的ID") key: str = Field(description="必须使用蛇形命名") value: str class Character(BaseModel): age: int name: str house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] properties: list[Property] = Field( ..., description="任意提取属性的编号列表,必须正好是5个", ) resp = client.chat.completions.create( model="gpt-4-1106-preview", messages=[{"role": "user", "content": "哈利·波特中的斯内普"}], response_model=Character, ) resp.model_dump()
输出[5]:
{'age': 38,
'name': 'Severus Snape',
'house': 'Slytherin',
'properties': [{'index': '1',
'key': 'position_at_hogwarts',
'value': 'Potions Master'},
{'index': '2', 'key': 'patronus_form', 'value': 'Doe'},
{'index': '3', 'key': 'loyalty', 'value': 'Albus Dumbledore'},
{'index': '4', 'key': 'played_by', 'value': 'Alan Rickman'},
{'index': '5', 'key': 'final_act', 'value': 'Protecting Harry Potter'}]} 定义多个实体¶
现在我们看到一个具有许多属性的单一实体,我们可以继续将它们嵌套到许多用户中
在 [6]:
Copied!
from collections.abc import Iterable
class Character(BaseModel):
age: int
name: str
house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]
resp = client.chat.completions.create(
model="gpt-4-1106-preview",
messages=[{"role": "user", "content": "Five characters from Harry Potter"}],
response_model=Iterable[Character],
)
for character in resp:
print(character)
从 collections.abc 导入 Iterable 类 Character(BaseModel): age: int name: str house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] resp = client.chat.completions.create( model="gpt-4-1106-preview", messages=[{"role": "user", "content": "五个来自哈利·波特的角色"}], response_model=Iterable[Character], ) 对于 character in resp: print(character)
age=11 name='Harry Potter' house='Gryffindor' age=11 name='Hermione Granger' house='Gryffindor' age=11 name='Ron Weasley' house='Gryffindor' age=11 name='Draco Malfoy' house='Slytherin' age=11 name='Neville Longbottom' house='Gryffindor'
在 [7]:
Copied!
from collections.abc import Iterable
class Character(BaseModel):
age: int
name: str
house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]
resp = client.chat.completions.create(
model="gpt-4-1106-preview",
messages=[{"role": "user", "content": "Five characters from Harry Potter"}],
stream=True,
response_model=Iterable[Character],
)
for character in resp:
print(character)
from collections.abc import Iterable class Character(BaseModel): age: int name: str house: Literal["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] resp = client.chat.completions.create( model="gpt-4-1106-preview", messages=[{"role": "user", "content": "来自哈利·波特的五个角色"}], stream=True, response_model=Iterable[Character], ) for character in resp: print(character)
age=11 name='Harry Potter' house='Gryffindor' age=11 name='Hermione Granger' house='Gryffindor' age=11 name='Ron Weasley' house='Gryffindor' age=17 name='Draco Malfoy' house='Slytherin' age=11 name='Luna Lovegood' house='Ravenclaw'
定义关系¶
我们不仅可以定义用户列表,还可以通过属性列表轻松定义引用列表。这是我学到的关于提示的更有趣的事情之一。
第 [8] 行:
Copied!
class Character(BaseModel):
id: int
name: str
friends_array: list[int] = Field(description="Relationships to their friends using the id")
resp = client.chat.completions.create(
model="gpt-4-1106-preview",
messages=[{"role": "user", "content": "5 kids from Harry Potter"}],
stream=True,
response_model=Iterable[Character],
)
for character in resp:
print(character)
class Character(BaseModel): id: int name: str friends_array: list[int] = Field(description="使用id与朋友的关系") resp = client.chat.completions.create( model="gpt-4-1106-preview", messages=[{"role": "user", "content": "5 kids from Harry Potter"}], stream=True, response_model=Iterable[Character], ) for character in resp: print(character)
id=1 name='Harry Potter' friends_array=[2, 3, 4, 5, 6] id=2 name='Hermione Granger' friends_array=[1, 3, 4, 5] id=3 name='Ron Weasley' friends_array=[1, 2, 4, 6] id=4 name='Neville Longbottom' friends_array=[1, 2, 3, 5] id=5 name='Luna Lovegood' friends_array=[1, 2, 4, 6] id=6 name='Draco Malfoy' friends_array=[1, 3, 5]
通过我们讨论的工具,我们可以在生产环境中找到许多实际应用。这些应用包括从记录中提取行动项、生成假数据、填写表单以及创建与生成式UI对应的对象。这些简单的技巧将非常有用。
缺失数据¶
Maybe模式是函数式编程中用于错误处理的一个概念。与抛出异常或返回None不同,你可以使用Maybe类型来封装结果和潜在的错误。
这种模式在进行LLM调用时特别有用,因为为语言模型提供一个逃生舱口可以有效减少幻觉。
在 [9]:
Copied!
from typing import Optional
class Character(BaseModel):
age: int
name: str
class MaybeCharacter(BaseModel):
result: Optional[Character] = Field(default=None)
error: bool = Field(default=False)
message: Optional[str]
来自 typing 导入可选的 class Character(基础模型): age:整数 name:字符串 class MaybeCharacter(基础模型): result:可选的[Character] = 字段(默认=无) error:布尔值 = 字段(默认=False) message:可选的[字符串]
在 [10]:
Copied!
def extract(content: str) -> MaybeCharacter:
return client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=MaybeCharacter,
messages=[
{"role": "user", "content": f"Extract `{content}`"},
],
)
def extract(content: str) -> MaybeCharacter: return client.chat.completions.create( model="gpt-3.5-turbo", response_model=MaybeCharacter, messages=[ {"role": "user", "content": f"提取 `{content}`"}, ], )
在 [11]:
Copied!
extract("Harry Potter")
提取("Harry Potter")
输出[11]:
MaybeCharacter(result=Character(age=17, name='Harry Potter'), error=False, message=None)
在 [12]:
Copied!
user = extract("404 Error")
if user.error:
raise ValueError(user.message)
用户 = extract("404 Error") 如果 用户.error: 引发 ValueError(用户.message)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) /Users/jasonliu/dev/instructor/docs/tutorials/2-tips.ipynb Cell 20 line 4 <a href='vscode-notebook-cell:/Users/jasonliu/dev/instructor/docs/tutorials/2-tips.ipynb#X25sZmlsZQ%3D%3D?line=0'>1</a> user = extract("404 Error") <a href='vscode-notebook-cell:/Users/jasonliu/dev/instructor/docs/tutorials/2-tips.ipynb#X25sZmlsZQ%3D%3D?line=2'>3</a> if user.error: ----> <a href='vscode-notebook-cell:/Users/jasonliu/dev/instructor/docs/tutorials/2-tips.ipynb#X25sZmlsZQ%3D%3D?line=3'>4</a> raise ValueError(user.message) ValueError: 404 Error