Extracting Thinking or Reasoning Content from LLM Model Responses in aisuite

aisuite automatically parses <thinking> tags from LLM responses, storing internal reasoning in Message.reasoning_content while keeping the final answer in Message.content.

aisuite provides a unified interface for multiple large language model providers, standardizing how developers interact with diverse APIs. When models return hidden chain-of-thought or reasoning steps wrapped in special tags, aisuite offers a built-in mechanism to extract and isolate this content from the final user-facing output.

How aisuite Extracts Reasoning Content

The <thinking> Tag Convention

aisuite looks for content wrapped in <thinking> tags at the start of a model's response. When the raw content begins with <thinking>, the framework treats everything between the opening and closing tags as internal reasoning to be separated from the public answer.

The Four-Step Extraction Process

According to the source code in aisuite/client.py, the _extract_thinking_content method implements a lightweight parsing pipeline:

  1. Detect the tag – Checks if the response content starts with <thinking>.
  2. Isolate reasoning – Extracts the string between <thinking> and </thinking> tags.
  3. Store separately – Assigns the extracted text to the reasoning_content attribute of the Message object, defined in aisuite/framework/message.py (lines 29-31).
  4. Clean visible output – Rewrites the content attribute to contain only the text appearing after the closing </thinking> tag.

After extraction, the normal response-handling pipeline emits a model.response event via _handle_model_response, making the reasoning available for tracing sinks and observability tools.

Accessing Reasoning Content in Your Code

After calling client.chat.completions.create(), you can inspect both the reasoning and the final answer through the response object's Message instance.

import aisuite

client = aisuite.Client()

response = client.chat.completions.create(
    model="openai:gpt-4o",
    messages=[{"role": "user", "content": "Explain the steps to solve this problem"}],
)

# Access the hidden reasoning

reasoning = response.choices[0].message.reasoning_content
print(f"Internal reasoning: {reasoning}")

# Access the final user-facing answer

answer = response.choices[0].message.content
print(f"Final answer: {answer}")

When a model returns content formatted as <thinking>The model's internal chain-of-thought...</thinking>\nHere is the final answer..., the reasoning_content field receives "The model's internal chain-of-thought..." while content becomes "Here is the final answer...".

Implementation Architecture

Message Model Extension

The Message class in aisuite/framework/message.py (lines 29-31) defines the reasoning_content attribute alongside the standard content field. This design keeps reasoning separate from public output while preserving it for downstream processing, debugging, or auditing.

Client-Side Processing

The extraction logic resides in aisuite/client.py within the _extract_thinking_content helper. This method modifies the response object in-place before it returns to the caller, ensuring that Message.reasoning_content contains the parsed reasoning and Message.content contains the sanitized visible text.

Testing the Extraction Logic

The test suite validates this behavior in tests/client/test_client.py (lines 18-33) through the test_chat_completions_extracts_thinking_content test case. This test verifies that when a mock response contains <thinking>private reasoning</thinking>\nFinal answer, the resulting Message object correctly stores "private reasoning" in reasoning_content and "Final answer" in content.

Summary

  • aisuite automatically extracts text wrapped in <thinking> tags from LLM responses when the content starts with the opening tag.
  • Extracted reasoning is stored in Message.reasoning_content, defined in aisuite/framework/message.py (lines 29-31).
  • The visible content field contains only the text after the closing </thinking> tag, hiding the reasoning from end users.
  • The extraction logic is implemented in _extract_thinking_content within aisuite/client.py.
  • Tracing events include the reasoning content via the standard model.response event pipeline.

Frequently Asked Questions

What tag format does aisuite use for reasoning extraction?

aisuite specifically looks for <thinking> tags at the beginning of the response content. The opening tag must appear immediately at the start of the text, with the reasoning content between <thinking> and </thinking>, followed by the final answer. Content not starting with <thinking> passes through unchanged with reasoning_content set to None.

How do I access the reasoning content after a chat completion?

Access the reasoning_content attribute on the Message object returned in the response choices: response.choices[0].message.reasoning_content. This field contains the extracted text from between the thinking tags, or None if no reasoning was detected during the extraction process.

Does aisuite modify the original response content when extracting reasoning?

Yes, aisuite rewrites the content field to remove the thinking tags and their contents. The content attribute will contain only the text that appeared after the closing </thinking> tag, ensuring end-users see only the final answer without the intermediate reasoning steps.

Can I manually inject reasoning content using this mechanism?

Yes, you can manually format your message content with <thinking> tags. If you construct a response or prompt with content formatted as <thinking>your reasoning here</thinking>\nyour final answer, aisuite will automatically parse and separate these components into the respective reasoning_content and content attributes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →