Thought / Action / Observation separation
You’re building a loop where the model can think, call tools, see results, and finally answer.
Separating Thought, Action, and Observation keeps that loop predictable and debuggable.
- Thought: model’s internal reasoning, in natural language.
- Action: a single structured command: which tool to call, with which arguments.
- Observation: the tool’s raw result, fed back into the model as context.
Why this separation matters
If the model’s reasoning is mixed with commands, your code can’t safely tell:
- what is just “thinking out loud”
- what is the actual tool call you must execute
By forcing the model into a pattern like:
- Think about the next step (
Thought:). - Either call one tool (
Action:) or produce the final answer (Final Answer:). - You then run the tool and feed back the result as
Observation:.
…the control flow is clear and your loop stays in charge.
You’re not letting the model execute code directly; you’re letting it propose actions that you inspect, parse, and run.
Concrete example
Let’s say you have tools:
search— calls a web search API.calculator— evaluates math expressions.
A single turn in your loop might look like this (model output):
textThought: I should first search for the current population of Berlin.
Action: search
Action Input: population of Berlin in 2024
Your code:
- Reads this.
- Extracts
tool_name = "search",tool_input = "population of Berlin in 2024". - Runs your
searchtool. - Gets an
Observation, e.g.:
Observation: The population of Berlin in 2024 is estimated to be about 3.8 million people.
- Appends this observation to the conversation.
- Calls the model again to continue.
Later, the model might output:
textThought: I now know the answer.
Final Answer: The population of Berlin in 2024 is about 3.8 million people.
Your loop sees Final Answer:, sends that back to the user, and stops.
Keep the Action part extremely regular (same labels, one tool, clear argument block) so your parser stays simple and safe.