Extracting Model Responses
The generate function completes the response instruction step by producing token IDs from a formatted test input.
Asking the Model for an Answer
Once a pretrained model is loaded, the next question is whether it can actually answer an instruction. In this step, the model is given the formatted input for one test set entry, asked to continue it, and the continuation is read back as text. That text is then placed next to the expected answer from the test set so the two can be compared.
The method is the same generate function that was used earlier to pretrain the model, so the familiar conversions between text and token IDs appear again. Three names carry the text forward through the program: input_text, token_ids, and generated_text. This article follows one pass through that loop closely, because the most useful skill here is knowing exactly which line produced which piece of text. When a response looks wrong, the cause is almost always found by tracing where the text changed shape.
What do you think happens?
Once the program finishes, does generated_text hold only the new words the model added, or something else?
Reveal answer
The prompt followed by the model's new words
generate returns token IDs for the prompt together with the newly produced tokens, and token_ids_to_text converts all of them back into one string. That is why generated_text still begins with the prompt.
How One Entry Becomes a Response
The source loop handles the first three entries of the test data. For each entry it formats the input, generates token IDs, converts those IDs back to text, and cleans up the response. Notice that the response is produced by slicing the generated text, not by the model returning a separate answer string. The model never receives the raw string directly: the formatted input is first converted into token IDs, generate produces a longer list of token IDs, and only then is that list converted back into text.
The generate function sits between the two conversions. It takes the encoded input, along with the model and the length limits, and returns token IDs. Decoding happens afterward, so the text you finally read was built from the full token sequence rather than from the model's answer alone. Keep the sequence in mind: text, then token IDs, then generated token IDs, then text again, then the slice, then the cleanup.
Why the Output Repeats the Prompt
The generated text contains both the input and the model's continuation. This is expected behavior, not a bug. A pretrained model is built to continue text coherently, and for a text-completion model the most natural output is a continuation that reads smoothly from the prompt. Returning the prompt together with the continuation therefore produces legible text.
Tracing One Test Entry Step by Step
Follow one test entry from start to finish, keeping a short written record of each variable. A useful habit from the source is to note the input text, the token IDs, the generated text, and the response at every line. The first record that looks unexpected tells you which line to inspect.
Tracing a single pass through the loop
A test entry has the input text Name a color. After generate runs, generated_text holds Name a color. Blue. Trace each value to find which part is the model's response.
- 1Record input_text
input_textis Name a color. It is 13 characters long, counting the period and not counting any trailing whitespace. - 2Record token_ids
The formatted input is encoded into token IDs, and generate returns a longer list containing those prompt IDs followed by the IDs for the new tokens.
- 3Record generated_text
token_ids_to_textconverts the full list back into one string, sogenerated_textis Name a color. Blue and still begins with the prompt. - 4Apply the slice
generated_text[len(input_text):] starts at position 13 and keeps everything after the prompt, which gives the string with a leading space followed by Blue. - 5Clean up
The cleanup step removes surrounding whitespace with
strip(), leaving Blue asresponse_text.
response_text is Blue, and it is the value printed next to the expected answer.
The Slice and strip() Line
The most important line in the loop is the slice generated_text[len(input_text):]. The source code assumes the generated text starts with the formatted input, which is why the code can measure the input's length and cut it off. The slice subtracts the length of the input from the start of generated_text, so it skips the first len(input_text) characters and keeps the rest.
Blueinput_textis the prompt that the model was givengenerated_textis the full string, prompt included- The slice skips the first
len(input_text)characters strip()acts on the slice result, not ongenerated_text
The two operations happen in a fixed order. The slice runs first, and strip() acts on what the slice returned. The slice does not change the prompt inside generated_text. Slicing produces a new string, so generated_text still contains the prompt after the slice, and only response_text holds the isolated answer.
raw_slice = generated_text[len(input_text):]raw_slice is ' Blue' with a leading space
response_text = raw_slice.strip()response_text is 'Blue'
The strip() function removes leading or trailing whitespace from the sliced result. It does not remove the prompt itself. That is why the slice must come first: if strip() were applied to the full generated text, the prompt would still be there, and the length-based cut would no longer line up with the original input.
The source also removes the string "### Response:" during cleanup. That marker is part of the prompt format rather than the answer, so it is removed along with the surrounding whitespace before the value is printed.
Locating Where a Comparison Diverges
Response generation is compared against the expected test set answers, so a mismatch points to the stage where the text changed unexpectedly. The fastest diagnosis is to check each value in the pipeline in order, and the first stage whose value differs from what you expected is where the result diverged.
- 1Check
input_textfirst and confirm it matches the formatted test entry. - 2Check
token_idsand confirm the prompt IDs appear at the start of the list. - 3Check
generated_textand confirm it begins withinput_text. - 4Check the sliced string and confirm it begins where the prompt ends.
- 5Check
response_textand compare it with the expected answer.
Common mistake Expecting generated_text to contain only the new words
What it looks likePrinting generated_text and seeing Name a color. Blue instead of Blue
Why it failsgenerate returns the prompt tokens together with the new tokens, and the decoded string keeps the prompt at its start
Do this insteadApply the slice to remove the prompt before treating the result as the response
Common mistake Calling strip() before the slice
What it looks likegenerated_text.strip()[len(input_text):]Why it failsStripping changes the length of the string, so the cut no longer matches the length of the prompt that was measured
Do this insteadSlice first, then call strip() on the sliced result
Common mistake Treating a response that still contains the question as a model failure
What it looks likeresponse_text still begins with the question text
Why it failsThe slice was skipped or applied to the wrong string, so the prompt was never removed
Do this insteadCheck that the slice is applied to generated_text and that input_text is the same string that was encoded
Common mistake Assuming a missing first character means the model made an error
What it looks likeresponse_text begins one character too late
Why it failsThe length measured from the prompt does not match the prompt that was actually used, so the cut lands one position off
Do this insteadCompare len(input_text) with the prompt that was actually encoded and fix the mismatch
Practicing the Trace
Suppose input_text is Hello world and generated_text is Hello world! Hi there. Without running anything, write what the slice generated_text[len(input_text):] keeps, then write the final response_text after strip().
Hints
- Count the characters in Hello world first, then skip exactly that many characters from
generated_text. - The slice keeps everything after the prompt, including the leading space before the continuation.
strip()removes only leading and trailing whitespace, not characters in the middle of the response.
What do you think happens?
After the slice and strip() run in that practice, does generated_text still contain Hello world?
Reveal answer
Yes, slicing produces a new string and leaves generated_text unchanged
Only response_text holds the isolated answer. The prompt remains inside generated_text.
Key Takeaways
- The generate function takes encoded input and returns token IDs for the prompt together with the newly produced tokens, and
token_ids_to_textturns them back intogenerated_text. generated_textcontains the prompt at its start because the model continues text, so the response must be isolated afterward.- The slice
generated_text[len(input_text):] removes the input prefix, andstrip()removes surrounding whitespace from that sliced result, in that order. - When a response looks wrong, check
input_text,token_ids,generated_text, the sliced string, andresponse_textin order to find where the text diverged.