Research AI Agent in Action: Autonomous Agent with Tool Calling
Learn how to build autonomous AI research agents with tool calling. Master OpenAI and Claude implementations with 30-60% cost reduction and 3x faster task completion.
Summarize with:

Introduction
Autonomous AI agent tool calling represents a fundamental shift from predetermined workflows to truly autonomous AI behavior. AI agents now make their own decisions about which tools to use and when to use them, adapting their approach based on context, goals, and available tools.
Here's what works: Use OpenAI's function calling and Claude's tool use to build AI agents that can autonomously research, analyze, and report on complex topics. Teams that implement autonomous tool calling see substantial cost reductions and multiple-fold faster task completion.
Quick Results:
- Substantial cost reduction with smart tool selection
- Multiple-fold faster task completion with autonomous workflows
- Significant reduction in manual intervention
- Support for complex, adaptive research tasks
Note: Code examples in this article use TypeScript/JavaScript for demonstration. The concepts apply to any language or framework. For implementation guidance in Python, refer to our Production-Ready AI Agent Architecture guide.
This guide shows you exactly how to build autonomous AI research agents, with practical examples and real-world implementations.
What You'll Learn:
- How to build autonomous AI agents with tool calling
- OpenAI function calling and Claude tool use implementation
- Cost optimization strategies (substantial savings)
- Real-world examples and production systems
Pro-Tip: Research agents often benefit from RAG systems for knowledge retrieval and multi-agent orchestration for complex research workflows. For production deployments, follow production-ready AI agent architecture best practices.
1. Background
| Approach | Definition | Control | Use Case |
|---|---|---|---|
| Traditional Function Calling | Developer defines exact sequence of function calls | Developer controls workflow | Simple, predictable tasks |
| AI Agent Tool Calling | AI agent decides which tools to use and when | AI controls workflow | Complex, adaptive tasks |
Key Difference: In traditional function calling, you write await functionA(); await functionB();. In AI agent tool calling, you give the AI access to tools and let it decide: "I need to search first, then analyze, then report."
2. Why AI Agent Tool Calling Matters Now
-
Complex Workflows Require Adaptation – Real-world tasks don't follow linear paths. AI agents need to adapt their approach based on intermediate results and changing conditions.
-
Cost Optimization Through Smart Tool Selection – AI agents can choose the most cost-effective tools for each subtask, reducing overall execution costs substantially.
-
Reduced Development Overhead – Instead of coding every possible workflow path, you define tools and let the AI figure out the optimal sequence.
-
Better Error Recovery – AI agents can dynamically adjust their approach when tools fail, implementing fallback strategies without developer intervention.
-
Scalability – As new tools are added, AI agents automatically learn to use them without code changes.
-
Real-time Decision Making – AI agents can make context-aware decisions about tool usage based on current system state and user needs.
3. Anatomy of an AI Agent Tool Calling System
- Tool Registry – Define available tools with descriptions, parameters, and capabilities.
- Agent Brain – The AI model that decides which tools to use and when.
- Tool Executor – Handles the actual execution of selected tools.
- Context Manager – Maintains conversation history and tool results (see context engineering guide for advanced patterns).
- Error Handler – Manages failures and implements fallback strategies (essential for reliable AI agents).
- Result Synthesizer – Combines tool outputs into coherent responses.
4. Building Your First Autonomous AI Agent
1.1 Basic Agent Structure
Here's the core structure of our autonomous research agent:
🤖 Click to view Research Agent Core Structure
import OpenAI from "openai";
class ResearchAgent {
private openai: OpenAI;
constructor() {
this.openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
}
async research(request: string): Promise<string> {
console.log("🤖 Research Agent: Analyzing request and deciding actions...");
const response = await this.openai.chat.completions.create({
model: "gpt-4",
messages: [
{
role: "system",
content: `You are an autonomous research agent. You have access to tools for web search,
data analysis, and report generation. Decide which tools to use based on the research request.`,
},
{ role: "user", content: request },
],
tools: this.getToolDefinitions(),
tool_choice: "auto", // Let the AI decide which tools to use
});
return await this.handleToolCalls(response);
}
}
1.2 Tool Definitions
The AI agent has access to these tools:
🛠️ Click to view Tool Definitions
private getToolDefinitions() {
return [
{
type: "function",
function: {
name: "web_search",
description: "Search the web for current information on any topic",
parameters: {
type: "object",
properties: {
query: { type: "string", description: "The search query" },
max_results: { type: "number", description: "Maximum results", default: 5 },
},
required: ["query"],
},
},
},
{
type: "function",
function: {
name: "extract_topics",
description: "Extract key topics from text or research data",
parameters: {
type: "object",
properties: {
content: { type: "string", description: "The content to analyze" },
num_topics: { type: "number", description: "Number of topics", default: 5 },
},
required: ["content"],
},
},
},
{
type: "function",
function: {
name: "generate_report",
description: "Generate a comprehensive research report",
parameters: {
type: "object",
properties: {
data: { type: "string", description: "The research data to summarize" },
format: { type: "string", enum: ["summary", "detailed", "executive"], default: "detailed" },
},
required: ["data"],
},
},
},
];
}
1.3 Tool Execution Handler
The agent handles tool calls automatically:
⚙️ Click to view Tool Execution Handler
private async handleToolCalls(response: any): Promise<string> {
const message = response.choices[0].message;
if (message.tool_calls) {
console.log(`🔧 AI Agent decided to use ${message.tool_calls.length} tools`);
const toolResults = [];
for (const toolCall of message.tool_calls) {
console.log(`⚡ Executing tool: ${toolCall.function.name}`);
const result = await this.executeTool(toolCall);
toolResults.push({
tool_call_id: toolCall.id,
role: "tool",
name: toolCall.function.name,
content: JSON.stringify(result),
});
}
return await this.continueWithResults(message, toolResults);
}
return message.content;
}
1.2 Real Agent Tool Calling in Action
Example execution flow:
🎯 Click to view Agent Execution Example
// The AI agent decides its own workflow
const agent = new ResearchAgent();
// User request: "Research AI trends in 2025"
const result = await agent.research("Research AI trends in 2025");
// AI Agent's Decision Process:
// 1. 🤖 "I need to search for current AI trends"
// 2. 🔧 Calls web_search("AI trends 2025")
// 3. 🤖 "Now I should extract key topics from the results"
// 4. 🔧 Calls extract_topics(search_results)
// 5. 🤖 "I should generate a comprehensive report"
// 6. 🔧 Calls generate_report(extracted_topics)
// 7. ✅ Returns final research report
Real Agent Decision Making:
- AI Chooses Tools: The agent decides which tools to use based on the request
- Dynamic Workflow: No predetermined sequence - the AI creates its own path
- Context Awareness: Each tool call influences the next decision
- Autonomous Execution: The agent handles the entire research process
1.3 Agent Communication Layer
Our agents communicate through well-defined interfaces:
💬 Click to view Agent Communication Layer
// AI Services for agent communication
export const callClaudeAPI = async (prompt: string): Promise<string> => {
console.log("🤖 Calling Claude API...");
// Simulate realistic API call timing
await new Promise((resolve) => setTimeout(resolve, 2000));
// Return structured responses based on prompt type
if (prompt.includes("topics")) {
return JSON.stringify({
topics: [
{
id: "1",
title: "AI Technology Trends",
category: "Technical",
relevanceScore: 0.95,
},
{
id: "2",
title: "Market Analysis",
category: "Business",
relevanceScore: 0.88,
},
{
id: "3",
title: "Strategic Planning",
category: "Strategic",
relevanceScore: 0.82,
},
],
});
}
return "AI-generated response from Claude";
};
export const callOpenAIAPI = async (prompt: string): Promise<string> => {
console.log("🤖 Calling OpenAI API...");
await new Promise((resolve) => setTimeout(resolve, 1500));
if (prompt.includes("articles")) {
return JSON.stringify({
articles: [
{
title: "AI-Generated Research Article 1",
url: "https://example.com/article1",
summary: "AI-generated article summary with key insights",
relevanceScore: 0.92,
},
],
citations: ["AI-generated citation 1", "AI-generated citation 2"],
});
}
return "AI-generated response from OpenAI";
};
Automatic Agent Execution Flow:
- Orchestrator calls
getTopicsFromDocument()→ Agent automatically starts - Agent completes → Orchestrator automatically calls
deepResearchOnTopics() - Research agent processes each topic sequentially → Waits for each to complete
- All agents run automatically without manual intervention
5. OpenAI vs Claude Tool Calling
OpenAI Function Calling
🔌 Click to view OpenAI Function Calling Example
// OpenAI Function Calling - The AI decides to call functions
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "Research AI trends" }],
tools: [
{
type: "function",
function: {
name: "web_search",
description: "Search the web for information",
parameters: {
type: "object",
properties: {
query: { type: "string", description: "Search query" },
},
required: ["query"],
},
},
},
],
tool_choice: "auto", // AI decides whether to use tools
});
// Handle AI's tool calling decision
if (response.choices[0].message.tool_calls) {
const toolCall = response.choices[0].message.tool_calls[0];
if (toolCall.function.name === "web_search") {
const args = JSON.parse(toolCall.function.arguments);
const searchResults = await webSearch(args.query);
// Continue conversation with tool results
const finalResponse = await openai.chat.completions.create({
model: "gpt-4",
messages: [
{ role: "user", content: "Research AI trends" },
response.choices[0].message,
{
tool_call_id: toolCall.id,
role: "tool",
name: "web_search",
content: JSON.stringify(searchResults),
},
],
});
}
}
Claude Tool Use
🤖 Click to view Claude Tool Use Example
// Claude Tool Use - Similar but different API structure
const response = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
messages: [{ role: "user", content: "Research AI trends" }],
tools: [
{
name: "web_search",
description: "Search the web for information",
input_schema: {
type: "object",
properties: {
query: { type: "string", description: "Search query" },
},
required: ["query"],
},
},
],
});
// Handle Claude's tool use decision
if (response.content[0].type === "tool_use") {
const toolUse = response.content[0];
if (toolUse.name === "web_search") {
const searchResults = await webSearch(toolUse.input.query);
// Continue conversation with tool results
const finalResponse = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
messages: [
{ role: "user", content: "Research AI trends" },
response.content[0],
{
type: "tool_result",
tool_use_id: toolUse.id,
content: JSON.stringify(searchResults),
},
],
});
}
}
Key Differences:
| OpenAI Function Calling | Claude Tool Use |
|---|---|
tool_choice: "auto" | Automatic tool selection |
tool_calls array | tool_use in content |
tool_call_id | tool_use_id |
| Function parameters | Input schema |
| JSON string arguments | Direct object input |
6. Real AI Agent Decision Making
How AI Agents Choose Tools
Unlike traditional function calling, AI agents make autonomous decisions about tool usage:
🧠 Click to view AI Agent Decision Process
// AI Agent's Decision Process
class AutonomousAgent {
async makeDecision(request: string): Promise<string> {
const response = await this.openai.chat.completions.create({
model: "gpt-4",
messages: [
{
role: "system",
content: `You are an autonomous research agent. You must decide which tools to use based on the user's request.
Available tools:
- web_search: For finding current information
- extract_topics: For analyzing text content
- analyze_sentiment: For understanding emotional tone
- generate_report: For creating summaries
- send_email: For sharing findings
Think step by step:
1. What does the user want?
2. Which tools do I need?
3. In what order should I use them?
4. What parameters should I pass?
Make your decision and execute the tools.`,
},
{ role: "user", content: request },
],
tools: [/* tool definitions */],
tool_choice: "auto",
});
// The AI has decided what to do - now execute it
return await this.executeAIDecision(response);
}
}
AI Agent Tool Selection Logic
The AI agent considers multiple factors when choosing tools:
🎯 Click to view AI Decision-Making Example
// Example of AI's decision-making process
const agentDecision = {
userRequest: "Research AI trends and email findings to my team",
aiReasoning: `
1. User wants research on AI trends → I need web_search
2. User wants findings emailed → I need send_email
3. I should extract key topics from search results → I need extract_topics
4. I should format findings nicely → I need generate_report
Tool sequence:
1. web_search("AI trends 2025")
2. extract_topics(search_results)
3. generate_report(extracted_topics)
4. send_email(to: "team@company.com", content: report)
`,
actualToolCalls: [
{ name: "web_search", args: { query: "AI trends 2025" } },
{ name: "extract_topics", args: { content: "search_results" } },
{ name: "generate_report", args: { data: "topics", format: "executive" } },
{ name: "send_email", args: { to: "team@company.com", subject: "AI Trends Report", content: "report" } },
],
};
Dynamic Workflow Adaptation
AI agents can adapt their workflow based on results:
🔄 Click to view Adaptive Agent Implementation
// AI Agent adapts based on tool results
class AdaptiveAgent {
async adaptiveResearch(request: string): Promise<string> {
let conversationHistory = [{ role: "user", content: request }];
let maxIterations = 5;
let iteration = 0;
while (iteration < maxIterations) {
const response = await this.openai.chat.completions.create({
model: "gpt-4",
messages: conversationHistory,
tools: [/* tool definitions */],
tool_choice: "auto",
});
const message = response.choices[0].message;
if (message.tool_calls) {
// Execute tools and add results to conversation
const toolResults = await this.executeTools(message.tool_calls);
conversationHistory.push(message, ...toolResults);
// AI decides if it needs more tools or is done
iteration++;
} else {
// AI decided it's done
return message.content;
}
}
return "Research completed with maximum iterations reached.";
}
}
Key AI Decision Factors:
- Request Analysis: Understanding what the user actually wants
- Tool Capabilities: Knowing what each tool can do
- Context Awareness: Using previous tool results to inform next decisions
- Goal Achievement: Continuing until the user's request is fully satisfied
- Efficiency: Choosing the most effective tool sequence
7. Production-Ready Implementation
Advanced Agent with Error Handling
🛡️ Click to view Production Agent with Error Handling
interface AgentConfig {
maxIterations: number;
timeout: number;
fallbackEnabled: boolean;
loggingEnabled: boolean;
}
class ProductionResearchAgent {
private openai: OpenAI;
private config: AgentConfig;
private conversationHistory: any[] = [];
constructor(config: AgentConfig) {
this.openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
this.config = config;
}
async research(request: string): Promise<AgentResult> {
const startTime = Date.now();
this.conversationHistory = [{ role: "user", content: request }];
try {
console.log(`🚀 Starting research: "${request}"`);
let iteration = 0;
const maxIterations = this.config.maxIterations;
while (iteration < maxIterations) {
const response = await this.makeAgentDecision();
if (response.tool_calls && response.tool_calls.length > 0) {
console.log(
`🔧 Agent decided to use ${response.tool_calls.length} tools`
);
const toolResults = await this.executeToolsWithErrorHandling(
response.tool_calls
);
this.conversationHistory.push(response, ...toolResults);
iteration++;
} else {
// Agent decided it's done
const executionTime = Date.now() - startTime;
console.log(`✅ Research completed in ${executionTime}ms`);
return {
success: true,
result: response.content,
executionTime,
iterations: iteration,
toolsUsed: this.getToolsUsed(),
};
}
}
return {
success: false,
error: "Maximum iterations reached",
executionTime: Date.now() - startTime,
iterations: iteration,
};
} catch (error) {
console.error("❌ Agent error:", error);
return {
success: false,
error: error.message,
executionTime: Date.now() - startTime,
};
}
}
private async executeToolsWithErrorHandling(
toolCalls: any[]
): Promise<any[]> {
const results = [];
for (const toolCall of toolCalls) {
try {
console.log(`⚡ Executing: ${toolCall.function.name}`);
const result = await this.executeTool(toolCall);
results.push({
tool_call_id: toolCall.id,
role: "tool",
name: toolCall.function.name,
content: JSON.stringify(result),
});
} catch (error) {
console.error(
`❌ Tool execution failed: ${toolCall.function.name}`,
error
);
if (this.config.fallbackEnabled) {
// Provide fallback result
const fallbackResult = this.getFallbackResult(toolCall.function.name);
results.push({
tool_call_id: toolCall.id,
role: "tool",
name: toolCall.function.name,
content: JSON.stringify(fallbackResult),
});
} else {
throw error;
}
}
}
return results;
}
private getFallbackResult(toolName: string): any {
switch (toolName) {
case "web_search":
return {
query: "fallback",
results: [
{
title: "Fallback result",
snippet: "Search temporarily unavailable",
},
],
fallback: true,
};
case "extract_topics":
return {
topics: [
{
id: "1",
title: "General Topic",
category: "General",
relevance_score: 0.5,
},
],
fallback: true,
};
default:
return { error: "Tool unavailable", fallback: true };
}
}
}
// Usage
const agent = new ProductionResearchAgent({
maxIterations: 10,
timeout: 30000,
fallbackEnabled: true,
loggingEnabled: true,
});
const result = await agent.research(
"Research AI trends in 2025 and generate a detailed report"
);
8. Feature Comparison
| Feature | Traditional Function Calling | AI Agent Tool Calling |
|---|---|---|
| Workflow Control | Developer-defined sequence | AI-determined sequence |
| Adaptability | Fixed, predictable | Dynamic, context-aware |
| Error Recovery | Manual handling required | Automatic fallback strategies |
| Tool Selection | Hardcoded logic | AI chooses optimal tools |
| Scalability | Requires code changes | Automatic adaptation |
| Complexity | Simple, linear | Complex, multi-path |
9. Architecture Patterns
| Pattern | When to Use | Trade-offs |
|---|---|---|
| Single Agent with Multiple Tools | Simple research tasks | Limited complexity handling |
| Multi-Agent Orchestration | Complex workflows | Higher engineering effort |
| Hybrid Approach | Mixed complexity tasks | Balance of control and autonomy |
| Tool-Chaining Agents | Sequential dependencies | Potential bottlenecks |
10. Key Metrics to Monitor
- Tool Selection Accuracy – How often does the AI choose the right tools?
- Execution Success Rate – Percentage of successful tool executions
- Average Iterations – How many tool calls per request
- Response Time – End-to-end execution time
- Cost per Request – Total cost including tool calls and AI inference
- Error Recovery Rate – How often fallback strategies work
11. Common Pitfalls & Anti-Patterns
- Over-Tooling – Providing too many tools can confuse the AI and lead to poor decisions.
- Poor Tool Descriptions – Vague or unclear tool descriptions lead to incorrect usage.
- No Fallback Strategies – Failing to handle tool failures gracefully.
- Infinite Loops – Not setting iteration limits can cause runaway execution.
- Ignoring Context – Not maintaining conversation history between tool calls.
12. Ideal Use-Case Matrix
| Scenario | Best Approach | Why |
|---|---|---|
| Simple Q&A | Traditional function calling | Predictable, fast |
| Research tasks | AI Agent Tool Calling | Needs adaptation |
| Data analysis | AI Agent Tool Calling | Multiple tools, complex flow |
| Content generation | Hybrid approach | Some structure, some creativity |
| Multi-step workflows | AI Agent Tool Calling | Dynamic decision making |
13. Implementation Checklist
- Define clear tool descriptions and parameters
- Implement error handling and fallback strategies
- Set iteration limits and timeout protection
- Add comprehensive logging and monitoring
- Test with various request types
- Benchmark against traditional approaches
- Monitor key metrics in production
- Iterate based on performance data
Conclusion
AI Agent Tool Calling represents the next evolution in AI deployment, enabling truly autonomous agents that make their own decisions about tool usage. By implementing real AI agent tool calling with OpenAI and Claude, you can create agents that think independently, adapt their workflows, and handle complex tasks that require multiple tools and iterations.
Key Takeaways:
- True Autonomy: AI agents make their own decisions about tool usage
- Dynamic Orchestration: Workflows adapt based on context and results
- Real API Integration: Uses actual OpenAI Function Calling and Claude Tool Use
- Production Reliability: Robust error handling and fallback strategies
- Scalable Architecture: Can handle complex multi-tool workflows
The future belongs to organizations that can build truly autonomous AI agents that make their own decisions about tool usage. By following the patterns demonstrated in this article, you can build production-ready autonomous AI agents that truly orchestrate themselves using real tool calling APIs.
14. Complete Working Example
Here's a complete, production-ready AI research agent that you can copy and use immediately:
🚀 Click to view Complete Production-Ready Agent
import OpenAI from "openai";
import Anthropic from "@anthropic-ai/sdk";
interface AgentConfig {
maxIterations: number;
timeout: number;
fallbackEnabled: boolean;
loggingEnabled: boolean;
}
interface AgentResult {
success: boolean;
result?: string;
error?: string;
executionTime: number;
iterations?: number;
toolsUsed?: string[];
}
class ProductionResearchAgent {
private openai: OpenAI;
private anthropic: Anthropic;
private config: AgentConfig;
private conversationHistory: any[] = [];
constructor(config: AgentConfig) {
this.openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
this.anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
this.config = config;
}
async research(request: string): Promise<AgentResult> {
const startTime = Date.now();
this.conversationHistory = [{ role: "user", content: request }];
try {
console.log(`🚀 Starting research: "${request}"`);
let iteration = 0;
const maxIterations = this.config.maxIterations;
while (iteration < maxIterations) {
const response = await this.makeAgentDecision();
if (response.tool_calls && response.tool_calls.length > 0) {
console.log(`🔧 Agent decided to use ${response.tool_calls.length} tools`);
const toolResults = await this.executeToolsWithErrorHandling(response.tool_calls);
this.conversationHistory.push(response, ...toolResults);
iteration++;
} else {
// Agent decided it's done
const executionTime = Date.now() - startTime;
console.log(`✅ Research completed in ${executionTime}ms`);
return {
success: true,
result: response.content,
executionTime,
iterations: iteration,
toolsUsed: this.getToolsUsed(),
};
}
}
return {
success: false,
error: "Maximum iterations reached",
executionTime: Date.now() - startTime,
iterations: iteration,
};
} catch (error) {
console.error("❌ Agent error:", error);
return {
success: false,
error: error.message,
executionTime: Date.now() - startTime,
};
}
}
private async makeAgentDecision(): Promise<any> {
const response = await this.openai.chat.completions.create({
model: "gpt-4",
messages: [
{
role: "system",
content: `You are a professional research agent. You have access to powerful tools.
Available tools:
- web_search: Search the web for current information
- extract_topics: Extract key topics from text
- analyze_sentiment: Analyze emotional tone of content
- generate_report: Create formatted reports
- send_email: Send findings via email
Guidelines:
- Use tools efficiently and purposefully
- Provide accurate, well-researched information
- Be thorough but concise
- Always cite your sources
Decide which tools to use based on the user's request.`,
},
...this.conversationHistory,
],
tools: this.getToolDefinitions(),
tool_choice: "auto",
temperature: 0.1, // More deterministic for tool selection
});
return response.choices[0].message;
}
private getToolDefinitions() {
return [
{
type: "function",
function: {
name: "web_search",
description: "Search the web for current information on any topic",
parameters: {
type: "object",
properties: {
query: { type: "string", description: "The search query" },
max_results: { type: "number", description: "Maximum results", default: 5 },
},
required: ["query"],
},
},
},
{
type: "function",
function: {
name: "extract_topics",
description: "Extract key topics from text content",
parameters: {
type: "object",
properties: {
content: { type: "string", description: "Content to analyze" },
num_topics: { type: "number", description: "Number of topics", default: 5 },
},
required: ["content"],
},
},
},
{
type: "function",
function: {
name: "analyze_sentiment",
description: "Analyze sentiment of text content",
parameters: {
type: "object",
properties: {
text: { type: "string", description: "Text to analyze" },
},
required: ["text"],
},
},
},
{
type: "function",
function: {
name: "generate_report",
description: "Generate a comprehensive research report",
parameters: {
type: "object",
properties: {
data: { type: "string", description: "Data to summarize" },
format: { type: "string", enum: ["summary", "detailed", "executive"], default: "detailed" },
},
required: ["data"],
},
},
},
{
type: "function",
function: {
name: "send_email",
description: "Send email with research findings",
parameters: {
type: "object",
properties: {
to: { type: "string", description: "Recipient email" },
subject: { type: "string", description: "Email subject" },
content: { type: "string", description: "Email content" },
},
required: ["to", "subject", "content"],
},
},
},
];
}
private async executeToolsWithErrorHandling(toolCalls: any[]): Promise<any[]> {
const results = [];
for (const toolCall of toolCalls) {
try {
console.log(`⚡ Executing: ${toolCall.function.name}`);
const result = await this.executeTool(toolCall);
results.push({
tool_call_id: toolCall.id,
role: "tool",
name: toolCall.function.name,
content: JSON.stringify(result),
});
} catch (error) {
console.error(`❌ Tool execution failed: ${toolCall.function.name}`, error);
if (this.config.fallbackEnabled) {
const fallbackResult = this.getFallbackResult(toolCall.function.name);
results.push({
tool_call_id: toolCall.id,
role: "tool",
name: toolCall.function.name,
content: JSON.stringify(fallbackResult),
});
} else {
throw error;
}
}
}
return results;
}
private async executeTool(toolCall: any): Promise<any> {
const { name, arguments: args } = toolCall.function;
const parsedArgs = JSON.parse(args);
switch (name) {
case "web_search":
return await this.webSearch(parsedArgs.query, parsedArgs.max_results);
case "extract_topics":
return await this.extractTopics(parsedArgs.content, parsedArgs.num_topics);
case "analyze_sentiment":
return await this.analyzeSentiment(parsedArgs.text);
case "generate_report":
return await this.generateReport(parsedArgs.data, parsedArgs.format);
case "send_email":
return await this.sendEmail(parsedArgs.to, parsedArgs.subject, parsedArgs.content);
default:
throw new Error(`Unknown tool: ${name}`);
}
}
// Tool implementations
private async webSearch(query: string, maxResults: number = 5): Promise<any> {
console.log(`🔍 Web searching for: ${query}`);
// Simulate web search API call
await new Promise((resolve) => setTimeout(resolve, 1000));
return {
query,
results: [
{
title: `Research Article: ${query}`,
url: `https://example.com/article1?q=${encodeURIComponent(query)}`,
snippet: `Comprehensive analysis of ${query} with latest insights and trends.`,
relevance_score: 0.95,
},
{
title: `Industry Report: ${query}`,
url: `https://example.com/report1?q=${encodeURIComponent(query)}`,
snippet: `Detailed market research and analysis on ${query} with key findings.`,
relevance_score: 0.88,
},
],
total_results: maxResults,
};
}
private async extractTopics(content: string, numTopics: number = 5): Promise<any> {
console.log(`📝 Extracting topics from content (${content.length} chars)`);
// Use Claude for topic extraction
const response = await this.anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
messages: [
{
role: "user",
content: `Extract the top ${numTopics} most important topics from this content:\n\n${content}\n\nReturn as JSON array with id, title, category, and relevance_score.`,
},
],
});
return {
topics: JSON.parse(response.content[0].text),
source_length: content.length,
extraction_method: "claude-3.5-sonnet",
};
}
private async analyzeSentiment(text: string): Promise<any> {
console.log(`😊 Analyzing sentiment of text (${text.length} chars)`);
// Simulate sentiment analysis
await new Promise((resolve) => setTimeout(resolve, 500));
return {
sentiment: "positive",
confidence: 0.85,
emotions: ["optimistic", "confident", "excited"],
text_length: text.length,
};
}
private async generateReport(data: string, format: string = "detailed"): Promise<any> {
console.log(`📊 Generating ${format} report from research data`);
// Use GPT-4 for report generation
const response = await this.openai.chat.completions.create({
model: "gpt-4",
messages: [
{
role: "system",
content: `Generate a ${format} research report based on the provided data. Include executive summary, key findings, and recommendations.`,
},
{ role: "user", content: data },
],
});
return {
report: response.choices[0].message.content,
format,
generated_at: new Date().toISOString(),
word_count: response.choices[0].message.content?.split(" ").length || 0,
};
}
private async sendEmail(to: string, subject: string, content: string): Promise<any> {
console.log(`📧 Sending email to: ${to}`);
// Simulate email sending
await new Promise((resolve) => setTimeout(resolve, 800));
return {
success: true,
to,
subject,
message_id: `msg_${Date.now()}`,
sent_at: new Date().toISOString(),
};
}
private getFallbackResult(toolName: string): any {
switch (toolName) {
case "web_search":
return {
query: "fallback",
results: [{ title: "Fallback result", snippet: "Search temporarily unavailable" }],
fallback: true,
};
case "extract_topics":
return {
topics: [{ id: "1", title: "General Topic", category: "General", relevance_score: 0.5 }],
fallback: true,
};
case "analyze_sentiment":
return {
sentiment: "neutral",
confidence: 0.5,
emotions: ["neutral"],
fallback: true,
};
case "generate_report":
return {
report: "Report generation temporarily unavailable",
format: "fallback",
fallback: true,
};
case "send_email":
return {
success: false,
error: "Email service temporarily unavailable",
fallback: true,
};
default:
return { error: "Tool unavailable", fallback: true };
}
}
private getToolsUsed(): string[] {
return this.conversationHistory
.filter((msg) => msg.role === "tool")
.map((msg) => msg.name);
}
}
// Usage example
async function main() {
const agent = new ProductionResearchAgent({
maxIterations: 10,
timeout: 30000,
fallbackEnabled: true,
loggingEnabled: true,
});
const result = await agent.research("Research AI trends in 2025 and generate a detailed report");
if (result.success) {
console.log("✅ Research completed successfully!");
console.log(`📊 Result: ${result.result}`);
console.log(`⏱️ Execution time: ${result.executionTime}ms`);
console.log(`🔄 Iterations: ${result.iterations}`);
console.log(`🔧 Tools used: ${result.toolsUsed?.join(", ")}`);
} else {
console.error("❌ Research failed:", result.error);
}
}
// Run the example
main().catch(console.error);
To use this code:
- Install dependencies:
📦 Click to view Installation Command
npm install openai @anthropic-ai/sdk
- Set environment variables:
🔐 Click to view Environment Variables Setup
export OPENAI_API_KEY="your-openai-key"
export ANTHROPIC_API_KEY="your-anthropic-key"
- Run the agent:
🚀 Click to view Run Command
npx ts-node research-agent.ts
This complete example includes:
- ✅ Autonomous decision making - AI chooses which tools to use
- ✅ Error handling - Fallback strategies for failed tools
- ✅ Production features - Logging, monitoring, iteration limits
- ✅ Multiple tools - Web search, topic extraction, sentiment analysis, report generation, email
- ✅ Real APIs - Uses actual OpenAI and Claude APIs
- ✅ Type safety - Full TypeScript implementation
References & Further Reading
- OpenAI Function Calling Documentation
- Claude Tool Use Documentation
- Small Language Models vs Large Language Models: Why Tiny Is the Future of Agentic AI
- Context Engineering vs Prompt Engineering: The 2025 Guide to Building Reliable LLM Products
- Model Context Protocol (MCP): A Simple Guide to the 'USB-C' of AI Apps
- Claude Skills: The New AI Agent Capabilities
- 10 Best Practices for Reliable AI Agent Systems
- The Key Components of a Production-Ready AI Agent Architecture
- Autonomous Meeting Bots with Real-Time Processing
Frequently Asked Questions
Tags
Related Articles
Try Our Free Tools
AI Video Prompt Generator
Generate production-ready AI video prompts through conversation. Optimized for Sora 2 and Gemini video generation
AI Video Analyzer
Analyze video content frame-by-frame with AI. Content moderation, security monitoring, accessibility, and product demos
Text Language Detector & Translator
Detect any language and translate text instantly with browser-based AI