In this tutorial, we will explore how to implement a chain of thoughts (COT) using the Mirascope library and the Groq Llama 3 model. Rather than blowing the model directly to an answer, COT reasoning encourages it to decompose the problem with logical steps, as the way a human would solve it. This approach improves precision, transparency and helps fight against complex tasks and in several stages in a more reliable way. We will guide you in the configuration of the scheme, the definition of reasoning calls step by step, the generation of final responses and the visualization of the reflection process in a structured manner.
We will ask the LLM a question of relative speed – “If a train leaves town at 9:00 am traveling at 60 km / h and another train leaves town B (300 km from city a) at 10:00 am traveling at 90 km / h towards city A, what time will the trains come together?“”
Dependencies installation
!pip install "mirascope(groq)"
!pip install datetime
API GROQ key
For this tutorial, we need an API groq key to make LLM calls. You can get one https://console.groq.com/keys
Import libraries and define a pydatic scheme
This section imports the required libraries and defines a dick pydatic model. The scheme structures each step of reasoning with a title, content and a next_ction indicator to indicate whether the model must continue to reason or return the final response.
from typing import Literal
from mirascope.core import groq
from pydantic import BaseModel, Field
history: list(dict) = ()
class COTResult(BaseModel):
title: str = Field(..., desecription="The title of the step")
content: str = Field(..., description="The output content of the step")
next_action: Literal("continue", "final_answer") = Field(
..., description="The next action to take"
)
Definition of stages reasoning and final response functions
These functions form the nucleus of the chain's chain reasoning flow (COT). The COT_STEP function allows the model to think in an iterative way by examining the previous steps and deciding to continue or conclude. This allows deeper reasoning, especially for problems in several stages. The Final_answer function consolidates all the reasoning in a single targeted response, which makes the exit clean and ready for the consumption of the end user. Together, they help the model to approach complex tasks in a more logical and transparent way.
@groq.call("llama-3.3-70b-versatile", json_mode=True, response_model=COTResult)
def cot_step(prompt: str, step_number: int, previous_steps: str) -> str:
return f"""
You are an expert AI assistant that explains your reasoning step by step.
For this step, provide a title that describes what you're doing, along with the content.
Decide if you need another step or if you're ready to give the final answer.
Guidelines:
- Use AT MOST 5 steps to derive the answer.
- Be aware of your limitations as an LLM and what you can and cannot do.
- In your reasoning, include exploration of alternative answers.
- Consider you may be wrong, and if you are wrong in your reasoning, where it would be.
- Fully test all other possibilities.
- YOU ARE ALLOWED TO BE WRONG. When you say you are re-examining
- Actually re-examine, and use another approach to do so.
- Do not just say you are re-examining.
IMPORTANT: Do not use code blocks or programming examples in your reasoning. Explain your process in plain language.
This is step number {step_number}.
Question: {prompt}
Previous steps:
{previous_steps}
"""
@groq.call("llama-3.3-70b-versatile")
def final_answer(prompt: str, reasoning: str) -> str:
return f"""
Based on the following chain of reasoning, provide a final answer to the question.
Only provide the text response without any titles or preambles.
Retain any formatting as instructed by the original prompt, such as exact formatting for free response or multiple choice.
Question: {prompt}
Reasoning:
{reasoning}
Final Answer:
"""
Generation and display of responses from the thought chain
This section defines two key functions to manage the complete chain reasoning loop:
- Generate_cot_respons manages the process of iterative reasoning. He sends the user request to the step by step model, follows the content, title and response time of each step, and stops when the model signals that he has reached the final answer or after a maximum of 5 steps. He then calls Final_answer to produce a clear conclusion based on accumulated reasoning.
- Display_cot_respons carefully prints the ventilation step by step with the time taken for each step, followed by the final response and the total processing time.
Together, these functions help to visualize the way in which the model reasons through a complex prompt and allows better transparency and debugging outings in several stages.
def generate_cot_response(
user_query: str,
) -> tuple(list(tuple(str, str, float)), float):
steps: list(tuple(str, str, float)) = ()
total_thinking_time: float = 0.0
step_count: int = 1
reasoning: str = ""
previous_steps: str = ""
while True:
start_time: datetime = datetime.now()
cot_result = cot_step(user_query, step_count, previous_steps)
end_time: datetime = datetime.now()
thinking_time: float = (end_time - start_time).total_seconds()
steps.append(
(
f"Step {step_count}: {cot_result.title}",
cot_result.content,
thinking_time,
)
)
total_thinking_time += thinking_time
reasoning += f"\n{cot_result.content}\n"
previous_steps += f"\n{cot_result.content}\n"
if cot_result.next_action == "final_answer" or step_count >= 5:
break
step_count += 1
# Generate final answer
start_time = datetime.now()
final_result: str = final_answer(user_query, reasoning).content
end_time = datetime.now()
thinking_time = (end_time - start_time).total_seconds()
total_thinking_time += thinking_time
steps.append(("Final Answer", final_result, thinking_time))
return steps, total_thinking_time
def display_cot_response(
steps: list(tuple(str, str, float)), total_thinking_time: float
) -> None:
for title, content, thinking_time in steps:
print(f"{title}:")
print(content.strip())
print(f"**Thinking time: {thinking_time:.2f} seconds**\n")
print(f"**Total thinking time: {total_thinking_time:.2f} seconds**")
Manage the workflow of the thought chain
The execution function initiates the complete reasoning process of the chain chain (COT) by sending a mathematical word problem in several stages to the model. He begins by printing the user's question, then uses Generate_Cot_respons to calculate a trace of reasoning step by step. These steps, as well as the total processing time, are displayed using the display_cot_respons.
Finally, the function records both the question and the final answer of the model in a shared history list, preserving the complete interaction for a reference or a future audit. This function is linked to all previous components in a full and user -oriented reasoning flow.
def run() -> None:
question: str = "If a train leaves City A at 9:00 AM traveling at 60 km/h, and another train leaves City B (which is 300 km away from City A) at 10:00 AM traveling at 90 km/h toward City A, at what time will the trains meet?"
print("(User):", question)
# Generate COT response
steps, total_thinking_time = generate_cot_response(question)
display_cot_response(steps, total_thinking_time)
# Add the interaction to the history
history.append({"role": "user", "content": question})
history.append(
{"role": "assistant", "content": steps(-1)(1)}
) # Add only the final answer to the history
# Run the function
run()
Discover the Codes. All the merit of this research goes to researchers in this project.
Sponsorship opportunity: Reach the most influential AI developers in the United States and Europe. 1M + monthly players, 500K + community manufacturers, endless possibilities. (Explore sponsorship)
