Parse ReAct Logs into Thought Action Observation Steps in Python
Parse a ReAct agent's textual log into structured steps with thought, action, and observation using regex and named tuples.
Python code
34 linesimport re
from collections import namedtuple
ReActStep = namedtuple("ReActStep", ["thought", "action", "observation"])
def parse_react_log(log: str) -> list[ReActStep]:
"""Parse a ReAct log into structured thought/action/observation steps."""
pattern = re.compile(
r"Thought:\s*(?P<thought>.+?)\s*"
r"Action:\s*(?P<action>\w+\[.*?\])\s*"
r"Observation:\s*(?P<observation>.+?)(?=\s*Thought:|\s*$)",
re.DOTALL
)
return [
ReActStep(m.group("thought"), m.group("action"), m.group("observation").strip())
for m in pattern.finditer(log)
]
if __name__ == "__main__":
sample_log = """
Thought: I need to check the weather.
Action: search[weather in London]
Observation: It's raining in London.
Thought: I should suggest an umbrella.
Action: reply[Bring an umbrella]
Observation: User thanks me.
"""
steps = parse_react_log(sample_log)
for i, step in enumerate(steps, 1):
print(f"Step {i}: thought={step.thought!r}, action={step.action!r}, observation={step.observation!r}")
Output
Step 1: thought='I need to check the weather.', action='search[weather in London]', observation="It's raining in London."
Step 2: thought='I should suggest an umbrella.', action='reply[Bring an umbrella]', observation='User thanks me.'
How it works
The code uses a compiled regex with named groups to capture each 'Thought:', 'Action:', and 'Observation:' segment. The re.DOTALL flag allows matching across newlines, and the lookahead (?=\s*Thought:|\s*$) stops each observation at the next thought or end of string. A namedtuple stores each step for structured access. The parse_react_log function returns a list of these tuples, making it easy to iterate and inspect agent reasoning traces.
Common mistakes
- Forgetting `re.DOTALL` causes the pattern to stop at newlines, breaking multi-line thoughts/observations.
- Using a plain tuple instead of namedtuple makes field access less readable.
- Assuming action quotes are always single quotes while logs may use double quotes.
Variations
- Use a dataclass with `@dataclass` instead of namedtuple for mutable or annotated steps.
- Add a `final` field or action output parser to extract arguments from the action string.
Real-world use cases
- Debugging LLM agents by logging and analyzing each reasoning step after a run.
- Building a replay or evaluation tool that reads saved ReAct transcripts to measure step quality.
- Converting agent logs into structured data for a vector store or monitoring dashboard.
Sponsored
More from AI & LLM integration patterns
- Cache LLM Completions by Hashing the Prompt in Python easy
- Chain of Thought Prompting in Python: Step-by-Step Reasoning Demo easy
- Circuit Breaker Pattern in Python for LLM API Calls medium
- Cosine Similarity to Retrieve Top K Chunks in Python easy
- Demonstrate Prompt Injection Bypass in Python easy
- How to Accumulate Streamed Tokens into a Final String in Python easy
Keep learning
Related tutorials and quizzes for this topic.