> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plaisolutions.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured Output

> Using non-streaming agents as tools, in workflows, and via API

When you disable **streaming** for an agent, it returns **structured JSON responses** instead of streamed text. You can optionally define a response schema so the JSON shape stays predictable and machine-readable every time, rather than open-ended prose.

***

## What is Structured Output?

**Structured Output** means:

* ✅ Agent returns complete response at once (not streamed)
* ✅ Response is formatted as JSON (not raw text)
* ✅ Can be used as a tool in other agents
* ✅ Can be used in workflows
* ✅ Can be called via API

```
Input:
"Analyze this customer feedback: [text]"

Output (Structured JSON):
{
  "sentiment": "positive",
  "confidence": 0.92,
  "topics": ["product_quality", "shipping_time"],
  "recommendations": ["Fast shipping appreciated"],
  "action_required": false
}
```

***

## Three Ways to Use Structured Output Agents

### 1. As a Tool in Other Agents

Use one agent as a **tool** that another agent can call:

Scenario: Sales Agent needs help with lead scoring.

1. **Sales Agent receives lead info**
2. **Calls "Lead Scorer" agent as a tool**
3. **Gets structured score & analysis** back
4. **Uses the score to prioritize the lead**

**Configuration:**

* Main Agent: Has "Lead Scorer" as a tool
* Lead Scorer: Non-streaming agent returning score JSON

**Example:**

```
Main Agent workflow:
1. Receive lead data
2. Call "Lead Scorer" tool
3. Get response: { score: 8, category: "hot" }
4. Route to appropriate team based on score
```

### 2. In Workflows

Use agent in **workflows** for multi-step automation:

Scenario: Daily data processing workflow.

1. **Extract Data** (API → Raw data)
2. **Validate Agent** (Non-streaming) → `{ valid: true, ... }`
3. **Transform Agent** (Non-streaming) → `{ normalized: {...} }`
4. **Load to Database** (API call)
5. **Result**: Clean data loaded

**Use cases:**

* Data validation and cleaning
* Content analysis and categorization
* Document extraction
* Quality assurance checks

### 3. Via API

Call agent directly through **REST API**:

```bash theme={null}
curl -X POST https://api.plai.com/agents/{slug}/invoke \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": "Summarize this article...",
    "agent_id": "content-summarizer"
  }'

Response:
{
  "id": "inv_12345",
  "status": "success",
  "output": {
    "summary": "This article discusses...",
    "key_points": [...],
    "confidence": 0.95
  },
  "metadata": {
    "tokens_used": 234,
    "duration_ms": 1200,
    "model": "claude-3.5-sonnet"
  }
}
```

***

## Configuring Structured Output

### In Agent Settings

1. Go to agent configuration
2. Find **Streaming** setting
3. **Disable** streaming
4. Optionally define **response schema** (JSON structure)

### Response Schema (Optional)

Define the expected JSON structure:

```json theme={null}
{
  "type": "object",
  "properties": {
    "sentiment": {
      "type": "string",
      "enum": ["positive", "negative", "neutral"]
    },
    "score": {
      "type": "number",
      "minimum": 0,
      "maximum": 1
    },
    "topics": {
      "type": "array",
      "items": { "type": "string" }
    }
  },
  "required": ["sentiment", "score"]
}
```

Benefits:

* ✅ Agent response always matches schema
* ✅ Easier to parse in code
* ✅ Better tool integration
* ✅ API contracts clearly defined

***

## Using as a Tool

### Adding Agent as Tool to Another Agent

<Steps>
  <Step title="Go to Main Agent Settings">
    Open the agent that will call other agents
  </Step>

  <Step title="Open Tools Tab">
    Navigate to Tools configuration
  </Step>

  <Step title="Add New Tool">
    Select "Agent" as tool type
  </Step>

  <Step title="Select Agent">
    Choose which agent to use as tool
  </Step>

  <Step title="Configure Parameters">
    Define what input to pass and how to use output
  </Step>

  <Step title="Save">
    Agent now available as tool
  </Step>
</Steps>

### Example: Agent Calling Agent

Scenario: Support Bot needs Lead Scoring Agent.

* **Support Bot Config**:
  * Name: Support Bot
  * Tools:
    * Help Desk API (for creating tickets)
    * Email Tool (for sending emails)
    * Lead Scorer Agent (for evaluating customers)
  * Prompt: "If customer mentions a sales opportunity, use the Lead Scorer agent to evaluate whether they're a good sales lead"

Flow example:

1. **User**: "I'm interested in your enterprise plan"
2. **Support Bot thinks**: "This is a sales opportunity"
3. **Support Bot calls Lead Scorer Agent**
   * Input: "Customer details and interest"
   * Output: `{ lead_score: 9, category: "hot", rec: "route_to_sales" }`
4. **Support Bot responds**: "Great! I'm connecting you with our sales team"

***

## Using in Workflows

### Workflow Integration

Example workflow: Customer Feedback Analysis

1. **Receive Feedback**
   * Input: Customer feedback text
   * Variable: `customer_feedback`
2. **Analyze with Agent**
   * Agent: "Feedback Analyzer" (non-streaming)
   * Input: `customer_feedback`
   * Output: `{ sentiment, topics, action_needed }`
3. **Route Based on Analysis**
   * If `action_needed == true` — create ticket in Help Desk
   * If `sentiment == "negative"` — alert support team
   * Else — archive
4. **Notify Stakeholders**
   * Send report with analysis
   * Done

### Conditional Routing with Agent Output

Agent returns:

```json theme={null}
{
  "priority": "high",
  "category": "billing",
  "needs_escalation": true
}
```

Workflow routes:

* If `priority == "high"` AND `needs_escalation` — escalate to manager
* Elif `category == "billing"` — route to billing team
* Else — route to general support

***

## API Usage

### REST API Endpoint

```
POST /api/agents/{agent_slug}/invoke
Authorization: Bearer {api_key}
Content-Type: application/json

Request Body:
{
  "input": "Your input text or data",
  "context": {
    "user_id": "optional_user_identifier",
    "session_id": "optional_session_id"
  }
}

Response:
{
  "id": "invocation_id",
  "status": "success|error|pending",
  "output": { /* agent response */ },
  "metadata": {
    "duration_ms": 1200,
    "tokens_used": 234,
    "model": "claude-3.5-sonnet"
  }
}
```

### Example: Node.js

```javascript theme={null}
const response = await fetch(
  'https://api.plai.com/agents/analyze-sentiment/invoke',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      input: 'This product exceeded expectations!',
      context: { user_id: 'user_123' }
    })
  }
);

const result = await response.json();
console.log(result.output);
// { sentiment: 'positive', confidence: 0.98, score: 9 }
```

### Example: Python

```python theme={null}
import requests

response = requests.post(
  'https://api.plai.com/agents/summarize-article/invoke',
  headers={
    'Authorization': f'Bearer {API_KEY}',
    'Content-Type': 'application/json'
  },
  json={
    'input': 'Article text here...',
    'context': {'article_id': 'art_456'}
  }
)

result = response.json()
print(result['output'])
# { 'summary': '...', 'key_points': [...] }
```

***

## Response Handling

### Successful Response

```json theme={null}
{
  "id": "inv_789",
  "status": "success",
  "output": {
    "result": "processed data",
    "confidence": 0.92
  },
  "metadata": {
    "tokens_used": 145,
    "duration_ms": 850,
    "timestamp": "2024-09-07T14:45:23Z"
  }
}
```

### Error Response

```json theme={null}
{
  "id": "inv_790",
  "status": "error",
  "error": {
    "code": "INVALID_INPUT",
    "message": "Input validation failed",
    "details": "Required field 'category' missing"
  },
  "metadata": {
    "timestamp": "2024-09-07T14:46:10Z"
  }
}
```

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Define Clear Schema" icon="squares">
    Specify response format so consumers know what to expect
  </Card>

  <Card title="Handle Errors" icon="alert">
    Always check status and error fields in responses
  </Card>

  <Card title="Use Context" icon="tag">
    Pass user\_id, session\_id, or other context for better tracking
  </Card>

  <Card title="Monitor Usage" icon="chart-line">
    Track API calls and token usage in project monitoring
  </Card>
</CardGroup>

### API Security

* ✅ Use API keys with appropriate permissions
* ✅ Rotate keys regularly
* ✅ Don't embed keys in frontend code
* ✅ Use environment variables or secrets manager
* ✅ Monitor for unusual API usage

***

## Comparing with Chat Mode

| Aspect             | Structured Output          | Chat (Streaming)    |
| ------------------ | -------------------------- | ------------------- |
| **Response**       | Complete JSON              | Streamed text       |
| **Interface**      | API/Tools/Workflows        | PLai Chat UI        |
| **Conversation**   | No history                 | Persistent history  |
| **Use Cases**      | Automation                 | User interaction    |
| **Multiple Calls** | Sequential                 | Sequential in UI    |
| **Response Time**  | One request → one response | Real-time streaming |

🔗 **Learn about Chat Mode:** [Conversational Chat](./conversational-chat.mdx)

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Agent returns empty response">
    **Check:**

    * Input format correct
    * Agent has proper datasources/tools
    * Response schema doesn't reject valid data
  </Accordion>

  <Accordion title="Schema validation fails">
    **Solutions:**

    * Review expected schema
    * Check agent prompt includes format instructions
    * Adjust schema to be less restrictive
  </Accordion>

  <Accordion title="API call times out">
    **Causes:**

    * Agent processing complex request
    * Tool calls taking too long
    * External API delays

    **Solution:** Increase timeout or optimize agent
  </Accordion>

  <Accordion title="Tool call from another agent fails">
    **Check:**

    * Tool agent is non-streaming
    * Tool agent is in same project
    * Tool agent has required datasources
    * Input format matches tool expectations
  </Accordion>
</AccordionGroup>

***

## Next Steps

* **[Configure Agent](./configuration.mdx)** - Set up structured output
* **[Workflows, Jobs & Triggers](../concepts/workflows-jobs-and-triggers.mdx)** - Use in workflows
* **[Use as Tool](../concepts/agents-datasources-and-tools.mdx#agents-as-tools)** - Agent calling agent
* **[API Documentation](../../api/agents.mdx)** - Full API reference
