Tornado Agent Basics
Overview
TornadoAgent is the core agent class in LlmTornado.Agents that provides a high-level abstraction for building AI agents. It combines AI models with tools, instructions, and structured output to create agents capable of performing complex tasks.
Quick Start
csharp
using LlmTornado;
using LlmTornado.Agents;
using LlmTornado.Chat.Models;
TornadoApi api = new TornadoApi("your-api-key");
// Create a simple agent
TornadoAgent agent = new TornadoAgent(
client: api,
model: ChatModel.OpenAi.Gpt41.V41Mini,
instructions: "You are a helpful assistant."
);
// Run the agent
Conversation result = await agent.RunAsync("Hello, what can you help me with?");
Console.WriteLine(result.Messages.Last().Content);Prerequisites
- LlmTornado.Agents package installed
- Understanding of basic LlmTornado chat functionality
- Familiarity with C# async/await patterns
TornadoAgent
TornadoAgent Architecture
A TornadoAgent consists of:
- Client: TornadoApi instance for API communication
- Model: The AI model powering the agent
- Instructions: System-level guidance defining behavior
- Tools: Functions the agent can call
- Output Schema: Optional type for structured responses
- Streaming: Real-time response capability
Agent Initialization
csharp
TornadoAgent agent = new TornadoAgent(
client: api, // Required: API client
model: ChatModel.OpenAi.Gpt4.O, // Required: AI model
name: "CodeAssistant", // Optional: Agent name
instructions: "You are a coding expert specialized in C#", // Optional: Behavior instructions
outputSchema: typeof(Response), // Optional: Structured output type
tools: toolsList, // Optional: Available functions
mcpServers: mcpList, // Optional: MCP servers
streaming: true, // Optional: Enable streaming
toolPermissionRequired: perms // Optional: Tool permissions
);Basic Usage
Simple Agent
csharp
TornadoAgent agent = new TornadoAgent(
client: api,
model: ChatModel.OpenAi.Gpt41.V41Mini,
instructions: "You are a helpful assistant."
);
Conversation result = await agent.RunAsync("What is 2+2?");
Console.WriteLine(result.Messages.Last().Content);Agent with Custom Instructions
csharp
string instructions = @"
You are a senior software architect with expertise in:
- Microservices architecture
- Cloud-native design patterns
- System scalability and performance
- Security best practices
Provide detailed, actionable advice with code examples when appropriate.
";
TornadoAgent agent = new TornadoAgent(
client: api,
model: ChatModel.OpenAi.Gpt4.O,
name: "ArchitectBot",
instructions: instructions
);
Conversation result = await agent.RunAsync(
"How should I design a scalable event-driven system?"
);Agent with Tools
csharp
TornadoAgent agent = new TornadoAgent(
client: api,
model: ChatModel.OpenAi.Gpt41.V41Mini,
instructions: "You are a helpful assistant that can check weather.",
tools: [weathertools.GetWeather]
);
Conversation result = await agent.RunAsync("What's the weather like in Prague?");
Console.WriteLine(result.Messages.Last().Content);
// Agent will call GetWeather("Prague") and use the result
public class weathertools
{
// Define a tool function
[Description("get the weather")]
public static string GetWeather([Description("cit to get weather from")] string city)
{
// Simulated weather data
return $"The weather in {city} is sunny with 22°C.";
}
}Agent with Structured Output
csharp
TornadoAgent agent = new TornadoAgent(
client: api,
model: ChatModel.OpenAi.Gpt4.O,
instructions: "Analyze tasks and provide structured breakdown.",
outputSchema: typeof(TaskAnalysis)
);
Conversation result = await agent.RunAsync("Analyze: Build a REST API with authentication");
TaskAnalysis? analysis = JsonConvert.DeserializeObject<TaskAnalysis>(
result.Messages.Last().Content
);
Console.WriteLine($"Task: {analysis?.Task}" +
$" Complexity: {analysis?.ComplexityScore} " +
$" Steps: {string.Join(", ", analysis?.Steps ?? Array.Empty<string>())} " +
$" Estimated Time: {analysis?.EstimatedMinutes} minutes");
public class TaskAnalysis
{
public string Task { get; set; }
public int ComplexityScore { get; set; }
public string[] Steps { get; set; }
public int EstimatedMinutes { get; set; }
}Advanced Usage
Maintaining Conversation Context
csharp
TornadoAgent agent = new TornadoAgent(api, ChatModel.OpenAi.Gpt41.V41Mini);
// First interaction
Conversation result = await agent.RunAsync("My name is Alice and I'm learning C#.");
// Continue conversation
result = await agent.RunAsync(
"What should I learn next?",
appendMessages: result.Messages.ToList()
);
// Agent remembers context
result = await agent.RunAsync(
"What's my name again?",
appendMessages: result.Messages.ToList()
);Dynamic Output Schema Changes
csharp
TornadoAgent agent = new TornadoAgent(
api,
ChatModel.OpenAi.Gpt4.O,
outputSchema: typeof(PersonInfo)
);
// Use initial schema
Conversation result = await agent.RunAsync("Extract: John, 30, NYC");
// Change schema dynamically
agent.UpdateOutputSchema(typeof(CompanyInfo));
// Use new schema
result = await agent.RunAsync("Extract: TechCorp, founded 2010, 500 employees");Adding Tools Dynamically
csharp
TornadoAgent agent = new TornadoAgent(api, ChatModel.OpenAi.Gpt41.V41);
// Add tool later
Tool weatherTool = new Tool(
(string city) => $"Weather in {city}: Sunny",
"get_weather",
"Gets weather for a city"
);
agent.AddTornadoTool(weatherTool);
Conversation result = await agent.RunAsync("What's the weather in London?");Best Practices
Clear Instructions
- Be specific about the agent's role
- Define boundaries and limitations
- Provide examples when helpful
- Use structured format for complex instructions
Tool Design
- Keep tools focused and single-purpose
- Provide clear descriptions
- Handle errors gracefully
- Return meaningful results
Error Handling
csharp
try
{
Conversation result = await agent.RunAsync(userInput);
if (!result.Messages.Any())
{
Console.WriteLine("No response generated");
return;
}
string response = result.Messages.Last().Content;
Console.WriteLine(response);
}
catch (Exception ex)
{
Console.WriteLine($"Agent error: {ex.Message}");
// Implement retry or fallback logic
}Memory Management
- Trim conversation history for long sessions
- Save important context to external storage
- Use conversation serialization for persistence
Common Issues
Agent Not Using Tools
Solutions:
- Ensure instructions mention tool availability
- Use models with strong function calling (GPT-4, Claude 3+)
- Provide clear tool descriptions
- Test tools individually first
Context Loss
Solutions:
- Always use
appendMessagesfor continuity - Implement conversation persistence
- Monitor token usage and trim history
Poor Output Quality
Solutions:
- Improve instruction clarity
- Use more capable models
- Provide examples in instructions
- Adjust temperature and other parameters
API Reference
Constructor
csharp
public TornadoAgent(
TornadoApi client,
ChatModel model,
string name = "Assistant",
string instructions = "You are a helpful assistant",
Type? outputSchema = null,
List<Delegate>? tools = null,
List<MCPServer>? mcpServers = null,
bool streaming = false,
Dictionary<string, bool>? toolPermissionRequired = null
)TornadoAgent Methods
RunAsync(string input, ...)- Execute agent with inputUpdateOutputSchema(Type? schema)- Change output format after initilization
TornadoAgent Properties
TornadoApi Client
TornadoApi required with authentication for api access to run the agent.
ChatModel Model
ChatModel desired to run on the agent while performing task. Close consideration should be taken when considering which model to use for each job.
ChatRequest Options
ChatRequest Used to configure any option within the specific api's to get a more advanced control. (Please set this after initilization)
ResponseRequest ResponseOptions
ResponseRequest Response Options to support OpenAI response Tools (Please set this after initilization)
string Name
Use to differentiate the agent when using as a tool or within the logging.
string Instructions
System message the agent will use as instructions for how to process users prompts
string Id
Unique generated GUID to differentiate agents on the backend
Type OutputSchema
The Type used to define the json stuctured output the agent should respond with.
List<Delegate> Tools
List of delegate functions used to extract tools from on initilization.
Dictionary<string, bool> ToolPermissionRequired
Set the Dictionary string Key as the tool name = true if you want the agent loop to send event for permission request.
Dictionary<string, Tool> ToolList
List of available Tornado tools that have been converted and ready to use within the agent loop
Dictionary<string, TornadoAgentTool> AgentTools
List of available Agents converted into Tornado tools and ready to be use within the agent loop
Dictionary<string, MCPServer> McpTools
List of available MCP tools as keys = MCP servers that host the tool required for the agent loop
List<MCPServer> MpcServers
List of MCP Servers to extract Tools from on initilization
bool Streaming
Used to enable to the default runner streaming capability if paired with a streaming handler. (or else it will not run streaming).
⚡ Event ⚡ Func<AgentRunnerEvents, ValueTask>? OnAgentRunnerEvent
Used to get Streaming Results, debugging information, tool results, ects.
Related Topics
- Agent Streaming - Real-time agent responses
- Structured Output - Type-safe agent responses
- Function Tools - Creating agent tools
- Persistent Conversations - Save and load agent state
- Tornado Runner - Advanced agent execution