Простая оценка с кодовым грейдингом
Простая оценка с кодовым грейдингом
В этом уроке мы начнем с рассмотрения очень простого примера оценки с кодовым грейдингом, прежде чем перейти к более реалистичному prompt в следующем уроке. Мы будем следовать процессу, изложенному на этой диаграмме:

Приблизительные шаги таковы: 1. Начните с определения нашего тестового набора для оценки 1. Напишите нашу первоначальную попытку prompt 2. Пропустите ее через наш процесс оценки и получите балл 3. Измените наш prompt на основе результатов оценки 4. Пропустите измененный prompt через наш процесс оценки и, будем надеяться, получите лучший балл!
Давайте попробуем следовать этому процессу!
Наши входные данные
Мы будем оценивать, где мы просим Claude успешно определить, сколько ног у животного. В будущих уроках мы увидим более сложные и реалистичные prompt'ы и оценки, но здесь мы намеренно упрощаем вещи, чтобы сосредоточиться на фактическом процессе оценки.
Первый шаг — написать наш набор данных для оценки, который включает наши входные данные плюс соответствующие эталонные ответы (golden answers). Давайте используем этот простой список словарей, где каждый словарь имеет ключи animal_statement и golden_answer:
eval_data = [
{"animal_statement": "The animal is a human.", "golden_answer": "2"},
{"animal_statement": "The animal is a snake.", "golden_answer": "0"},
{"animal_statement": "The fox lost a leg, but then magically grew back the leg he lost and a mysterious extra leg on top of that.", "golden_answer": "5"},
{"animal_statement": "The animal is a dog.", "golden_answer": "4"},
{"animal_statement": "The animal is a cat with two extra legs.", "golden_answer": "6"},
{"animal_statement": "The animal is an elephant.", "golden_answer": "4"},
{"animal_statement": "The animal is a bird.", "golden_answer": "2"},
{"animal_statement": "The animal is a fish.", "golden_answer": "0"},
{"animal_statement": "The animal is a spider with two extra legs", "golden_answer": "10"},
{"animal_statement": "The animal is an octopus.", "golden_answer": "8"},
{"animal_statement": "The animal is an octopus that lost two legs and then regrew three legs.", "golden_answer": "9"},
{"animal_statement": "The animal is a two-headed, eight-legged mythical creature.", "golden_answer": "8"},
]
Обратите внимание, что некоторые вопросы для оценки немного хитрые, например, этот:
Лиса потеряла ногу, но затем волшебным образом отрастила потерянную ногу и вдобавок загадочную лишнюю ногу.
Это будет важно позже!
Наш первоначальный prompt
Далее мы определим наш первоначальный prompt. Функция ниже принимает одно утверждение о животном и возвращает правильно отформатированный список сообщений, содержащий нашу первую попытку prompt:
def build_input_prompt(animal_statement):
user_content = f"""You will be provided a statement about an animal and your job is to determine how many legs that animal has.
Here is the animal statement.
<animal_statement>{animal_statement}</animal_statement>
How many legs does the animal have? Please respond with a number"""
messages = [{'role': 'user', 'content': user_content}]
return messages
Давайте быстро протестируем его с первым элементом нашего набора данных eval:
build_input_prompt(eval_data[0]['animal_statement'])
[{'role': 'user',
'content': 'You will be provided a statement about an animal and your job is to determine how many legs that animal has.\n \n Here is the animal statement.\n <animal_statement>The animal is a human.</animal_statement>\n \n How many legs does the animal have? Please respond with a number'}]
Далее мы напишем простую функцию, которая принимает список сообщений и отправляет его в Anthropic API:
from anthropic import Anthropic
from dotenv import load_dotenv
load_dotenv()
client = Anthropic()
MODEL_NAME = "claude-3-haiku-20240307"
def get_completion(messages):
response = client.messages.create(
model=MODEL_NAME,
max_tokens=200,
messages=messages
)
return response.content[0].text
Давайте протестируем его с нашей первой записью в списке eval_data, которая содержит следующее утверждение о животном:
'The animal is a human.'
full_prompt = build_input_prompt(eval_data[0]['animal_statement'])
get_completion(full_prompt)
'2'
Мы получаем 2 в ответ, что проходит "визуальный тест"! У людей обычно две ноги. Следующий шаг — построить и запустить полную оценку со всеми 12 записями в нашем наборе eval_data.
Написание логики оценки
Мы начнем с объединения каждого входа из нашего списка eval_data с нашим шаблоном prompt, передачи полученных "готовых" prompt'ов модели и сбора всех полученных нами выходных данных:
outputs = [get_completion(build_input_prompt(question['animal_statement'])) for question in eval_data]
Давайте быстро взглянем на то, что мы получаем в ответ:
outputs
['2',
'0',
'5',
'4',
'6',
'4',
'Based on the provided animal statement, "The animal is a bird.", the animal has 2 legs.\n\nResponse: 2',
'0',
'8',
'An octopus has 8 legs.',
'5',
'8']
Уже сейчас мы можем сказать, что наш prompt нуждается в улучшении, потому что мы получаем некоторые ответы, которые не являются исключительно числами! Давайте внимательнее рассмотрим результаты вместе с каждым соответствующим эталонным ответом (golden answer):
for output, question in zip(outputs, eval_data):
print(f"Animal Statement: {question['animal_statement']}\nGolden Answer: {question['golden_answer']}\nOutput: {output}\n")
Animal Statement: The animal is a human.
Golden Answer: 2
Output: 2
Animal Statement: The animal is a snake.
Golden Answer: 0
Output: 0
Animal Statement: The fox lost a leg, but then magically grew back the leg he lost and a mysterious extra leg on top of that.
Golden Answer: 5
Output: 5
Animal Statement: The animal is a dog.
Golden Answer: 4
Output: 4
Animal Statement: The animal is a cat with two extra legs.
Golden Answer: 6
Output: 6
Animal Statement: The animal is an elephant.
Golden Answer: 4
Output: 4
Animal Statement: The animal is a bird.
Golden Answer: 2
Output: Based on the provided animal statement, "The animal is a bird.", the animal has 2 legs.
Response: 2
Animal Statement: The animal is a fish.
Golden Answer: 0
Output: 0
Animal Statement: The animal is a spider with two extra legs
Golden Answer: 10
Output: 8
Animal Statement: The animal is an octopus.
Golden Answer: 8
Output: An octopus has 8 legs.
Animal Statement: The animal is an octopus that lost two legs and then regrew three legs.
Golden Answer: 9
Output: 5
Animal Statement: The animal is a two-headed, eight-legged mythical creature.
Golden Answer: 8
Output: 8
Это достаточно маленький набор данных, чтобы мы могли легко просканировать результаты и найти проблемные ответы, но давайте оценим наши результаты систематически:
def grade_completion(output, golden_answer):
return output == golden_answer
grades = [grade_completion(output, question['golden_answer']) for output, question in zip(outputs, eval_data)]
print(f"Score: {sum(grades)/len(grades)*100}%")
Score: 66.66666666666666%
Теперь у нас есть базовый балл! В этом случае наш первоначальный prompt привел к точности 66,6%. После сканирования вышеуказанных результатов, похоже, есть две очевидные проблемы с нашими текущими выходными данными:
Проблема 1: Проблемы с форматированием вывода
Наша цель здесь — написать prompt, который приводит к числовому выводу. Некоторые из наших выходных данных не являются числовыми:
Animal Statement: The animal is a bird.
Golden Answer: 2
Output: Based on the provided animal statement, "The animal is a bird.", the animal has 2 legs.
Мы можем исправить это с помощью prompt'инга!
Проблема 1: Неправильные ответы
Кроме того, некоторые ответы совершенно неверны:
Animal Statement: The animal is an octopus that lost two legs and then regrew three legs.
Golden Answer: 9
Output: 5
и
Animal Statement: The animal is a spider with two extra legs
Golden Answer: 10
Output: 8
Эти входные данные немного "хитрые" и, кажется, вызывают некоторые проблемы у модели. Мы также попытаемся исправить это с помощью prompt'инга!
Наша вторая попытка
Теперь, когда у нас есть некоторый базовый уровень производительности с нашим первоначальным prompt'ом, давайте попробуем улучшить prompt и посмотреть, улучшится ли наш балл оценки. Мы начнем с решения проблемы, когда модель иногда выводит дополнительный текст вместо того, чтобы отвечать только числовой цифрой. Вот вторая функция для генерации prompt'а:
def build_input_prompt2(animal_statement):
user_content = f"""You will be provided a statement about an animal and your job is to determine how many legs that animal has.
Here is the animal statement.
<animal_statement>{animal_statement}</animal_statement>
How many legs does the animal have? Respond only with a numeric digit, like 2 or 6, and nothing else."""
messages = [{'role': 'user', 'content': user_content}]
return messages
Ключевое дополнение к prompt'у — эта строка:
Отвечайте только числовой цифрой, например 2 или 6, и ничем иным.
Давайте протестируем каждый ввод с этим новым prompt'ом:
outputs2 = [get_completion(build_input_prompt2(question['animal_statement'])) for question in eval_data]
Давайте быстро взглянем на выходные данные:
outputs2
['2', '0', '6', '4', '6', '4', '2', '0', '8', '8', '5', '8']
Теперь мы получаем исключительно числовые выходные данные! Давайте внимательнее рассмотрим результаты:
for output, question in zip(outputs2, eval_data):
print(f"Animal Statement: {question['animal_statement']}\nGolden Answer: {question['golden_answer']}\nOutput: {output}\n")
Animal Statement: The animal is a human.
Golden Answer: 2
Output: 2
Animal Statement: The animal is a snake.
Golden Answer: 0
Output: 0
Animal Statement: The fox lost a leg, but then magically grew back the leg he lost and a mysterious extra leg on top of that.
Golden Answer: 5
Output: 6
Animal Statement: The animal is a dog.
Golden Answer: 4
Output: 4
Animal Statement: The animal is a cat with two extra legs.
Golden Answer: 6
Output: 6
Animal Statement: The animal is an elephant.
Golden Answer: 4
Output: 4
Animal Statement: The animal is a bird.
Golden Answer: 2
Output: 2
Animal Statement: The animal is a fish.
Golden Answer: 0
Output: 0
Animal Statement: The animal is a spider with two extra legs
Golden Answer: 10
Output: 8
Animal Statement: The animal is an octopus.
Golden Answer: 8
Output: 8
Animal Statement: The animal is an octopus that lost two legs and then regrew three legs.
Golden Answer: 9
Output: 5
Animal Statement: The animal is a two-headed, eight-legged mythical creature.
Golden Answer: 8
Output: 8
Все еще есть очевидные проблемы с фактическими числовыми ответами, например, с этим:
Animal Statement: The animal is a spider with two extra legs
Golden Answer: 10
Output: 8
Прежде чем решать эту проблему, давайте получим официальный балл, чтобы увидеть, как наша производительность (надеемся) улучшилась:
grades = [grade_completion(output, question['golden_answer']) for output, question in zip(outputs2, eval_data)]
print(f"Score: {sum(grades)/len(grades)*100}%")
Score: 75.0%
Наш балл немного увеличился! Примечание: этот набор данных довольно мал, поэтому относитесь к этим результатам с долей скептицизма
Наша третья попытка
Далее давайте разберемся с логическими проблемами, которые мы видим в некорректных выходных данных, такими как:
Animal Statement: The fox lost a leg, but then magically grew back the leg he lost and a mysterious extra leg on top of that.
Golden Answer: 5
Output: 6
Один из методов, который мы могли бы применить здесь, — это prompt'инг "цепочки рассуждений" (chain of thought prompting), когда мы даем Claude конкретные инструкции рассуждать над своим ответом, прежде чем окончательно сгенерировать его. Теперь, когда у нас есть оценка, мы можем проверить, действительно ли prompt'инг "цепочки рассуждений" имеет значение!
Давайте напишем новый prompt, который просит модель "думать вслух" внутри тегов <thinking>. Это немного усложняет нашу логику, потому что нам понадобится удобный способ извлечь окончательный ответ модели. Мы проинструктируем модель также включать свой окончательный ответ внутри тегов <answer>, чтобы мы могли легко извлечь "конечный" числовой ответ:
def build_input_prompt3(animal_statement):
user_content = f"""You will be provided a statement about an animal and your job is to determine how many legs that animal has.
Here is the animal statement.
<animal_statement>{animal_statement}</animal_statement>
How many legs does the animal have?
Start by reasoning about the numbers of legs the animal has, thinking step by step inside of <thinking> tags.
Then, output your final answer inside of <answer> tags.
Inside the <answer> tags return just the number of legs as an integer and nothing else."""
messages = [{'role': 'user', 'content': user_content}]
return messages
Давайте соберем выходные данные, используя эту новую версию prompt'а:
outputs3 = [get_completion(build_input_prompt3(question['animal_statement'])) for question in eval_data]
Теперь давайте взглянем на некоторые из выходных данных:
for output, question in zip(outputs3, eval_data):
print(f"Animal Statement: {question['animal_statement']}\nGolden Answer: {question['golden_answer']}\nOutput: {output}\n")
Animal Statement: The animal is a human.
Golden Answer: 2
Output: <thinking>
The animal is a human, and based on this information, we can reasonably conclude that a human has 2 legs. Humans are bipedal, meaning they have two legs that they use for locomotion and standing upright. This is a characteristic of the human species.
</thinking>
<answer>2</answer>
Animal Statement: The animal is a snake.
Golden Answer: 0
Output: <thinking>
The animal stated in the given statement is a snake. Snakes are known to be legless reptiles, as they do not have any legs. They move by slithering on the ground using their body and scales.
</thinking>
<answer>0</answer>
Animal Statement: The fox lost a leg, but then magically grew back the leg he lost and a mysterious extra leg on top of that.
Golden Answer: 5
Output: Here is my step-by-step reasoning:
<thinking>
1. The initial statement says the fox lost a leg.
2. But then the fox "magically grew back the leg he lost and a mysterious extra leg on top of that."
3. This means the fox originally had 4 legs, lost 1 leg, and then grew back the lost leg plus an extra leg, for a total of 5 legs.
</thinking>
<answer>5</answer>
Animal Statement: The animal is a dog.
Golden Answer: 4
Output: <thinking>
The animal statement says the animal is a dog. Dogs are quadrupeds, meaning they have four legs. Therefore, the number of legs the dog has is 4.
</thinking>
<answer>4</answer>
Animal Statement: The animal is a cat with two extra legs.
Golden Answer: 6
Output: <thinking>
The animal statement says that the animal is a cat with two extra legs. A typical cat has four legs, so with the two extra legs, the animal must have six legs in total.
</thinking>
<answer>6</answer>
Animal Statement: The animal is an elephant.
Golden Answer: 4
Output: <thinking>
An elephant is a large mammal that belongs to the order Proboscidea. Elephants are known to have four legs, one for each of their four limbs. Therefore, based on the given animal statement, the animal is an elephant, and elephants have four legs.
</thinking>
<answer>4</answer>
Animal Statement: The animal is a bird.
Golden Answer: 2
Output: <thinking>
The statement provided indicates that the animal is a bird. Birds typically have two legs, as they are bipedal animals that walk and perch on two legs.
</thinking>
<answer>2</answer>
Animal Statement: The animal is a fish.
Golden Answer: 0
Output: <thinking>
Based on the given animal statement, the animal is a fish. Fish are aquatic vertebrates that typically have fins and gills to help them swim and breathe in the water. Fish do not have legs, as they move through the water using their fins and tails.
</thinking>
<answer>0</answer>
Animal Statement: The animal is a spider with two extra legs
Golden Answer: 10
Output: <thinking>
The animal statement says that the animal is a spider with two extra legs.
A spider typically has 8 legs, so with two extra legs, the total number of legs would be 8 + 2 = 10 legs.
</thinking>
<answer>10</answer>
Animal Statement: The animal is an octopus.
Golden Answer: 8
Output: <thinking>
The animal statement says the animal is an octopus. An octopus is a marine invertebrate with eight tentacles that are often referred to as legs. Therefore, the animal has 8 legs.
</thinking>
<answer>8</answer>
Animal Statement: The animal is an octopus that lost two legs and then regrew three legs.
Golden Answer: 9
Output: <thinking>
The animal is described as an octopus that lost two legs and then regrew three legs. Initially, an octopus has eight legs.
Since the animal lost two legs, it would have had six legs remaining.
Then, the animal regrew three legs, so the final number of legs the animal has is nine.
</thinking>
<answer>9</answer>
Animal Statement: The animal is a two-headed, eight-legged mythical creature.
Golden Answer: 8
Output: <thinking>
The animal statement mentions that the animal is a two-headed, eight-legged mythical creature. This means that the animal has two heads and eight legs.
</thinking>
<answer>8</answer>
Вот пример того, какой ответ мы получаем:
Animal Statement: The fox lost a leg, but then magically grew back the leg he lost and a mysterious extra leg on top of that.
Golden Answer: 5
Output: Here is my step-by-step reasoning:
<thinking>
1. The initial statement says the fox lost a leg.
2. But then the fox "magically grew back the leg he lost and a mysterious extra leg on top of that."
3. This means the fox originally had 4 legs, lost 1 leg, and then grew back the lost leg plus an extra leg, for a total of 5 legs.
</thinking>
<answer>5</answer>
Логика, кажется, улучшилась, по крайней мере, в этом конкретном примере. Теперь нам нужно сосредоточиться на том, чтобы сделать этот prompt "оцениваемым". Нам нужно извлечь число между тегами answer перед процессом оценки.
Вот функция, которая извлекает текст между двумя тегами <answer>:
import re
def extract_answer(text):
pattern = r'<answer>(.*?)</answer>'
match = re.search(pattern, text)
if match:
return match.group(1)
else:
return None
Далее давайте извлечем ответы из последней партии выходных данных:
extracted_outputs3 = [extract_answer(output) for output in outputs3]
extracted_outputs3
['2', '0', '5', '4', '6', '4', '2', '0', '10', '8', '9', '8']
Далее давайте получим наш балл и посмотрим, повлияло ли добавление "цепочки рассуждений" к нашему prompt'у!
grades3 = [grade_completion(output, question['golden_answer']) for output, question in zip(extracted_outputs3, eval_data)]
print(f"Score: {sum(grades3)/len(grades3)*100}%")
Score: 100.0%
Мы улучшили наш балл до 100%!
Наша оценка дает нам некоторую уверенность в том, что изменения, которые мы внесли в наш prompt, действительно приводят к лучшим результатам. Это простой пример, использующий точное совпадение при грейдинге, но в следующем уроке мы рассмотрим нечто более сложное.