Development Framework Integration: LangChain, OpenRouter, Together AI & Custom Solutions

Master AI development frameworks including LangChain, OpenRouter, Together AI, and custom provider integrations. Learn setup, optimization, and best practices.

Learn how to integrate and optimize AI development frameworks for efficient model management. This guide covers LangChain, OpenRouter, Together AI, and custom provider solutions with practical implementation examples.

Framework Comparison Overview

Framework Capabilities

FrameworkTypeStrengthsBest ForCost Model
LangChainOrchestrationComprehensive ecosystem, chainsComplex workflows, RAGFree (OSS) + provider costs
OpenRouterAPI GatewayModel routing, unified APIModel experimentationPay-per-token + markup
Together AIHosting PlatformOpen source models, fine-tuningCustom models, inferencePay-per-token
Custom SolutionsDIYFull control, optimizationSpecific requirementsDevelopment time + hosting

:::tip Framework Selection Strategy Use LangChain for complex AI workflows, OpenRouter for model experimentation and unified access, Together AI for open-source model hosting, and custom solutions for specific optimization needs. :::

LangChain Integration

Setup and Basic Configuration

// LangChain setup with multiple providers
import { ChatOpenAI } from '@langchain/openai';
import { ChatAnthropic } from '@langchain/anthropic';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { PromptTemplate } from '@langchain/core/prompts';
import { StringOutputParser } from '@langchain/core/output_parsers';
import { RunnableSequence } from '@langchain/core/runnables';

// Provider configuration
const providers = {
  openai: new ChatOpenAI({
    apiKey: process.env.OPENAI_API_KEY,
    model: 'gpt-4',
    temperature: 0.7,
    maxTokens: 1000,
  }),
  
  anthropic: new ChatAnthropic({
    apiKey: process.env.ANTHROPIC_API_KEY,
    model: 'claude-3-5-sonnet-20241022',
    temperature: 0.7,
    maxTokens: 1000,
  }),
  
  google: new ChatGoogleGenerativeAI({
    apiKey: process.env.GOOGLE_AI_API_KEY,
    model: 'gemini-pro',
    temperature: 0.7,
    maxOutputTokens: 1000,
  })
};

// Basic chain creation
async function createBasicChain(providerName = 'openai') {
  const model = providers[providerName];
  
  const prompt = PromptTemplate.fromTemplate(
    "Answer the following question: {question}"
  );
  
  const chain = RunnableSequence.from([
    prompt,
    model,
    new StringOutputParser()
  ]);
  
  return chain;
}

// Usage example
async function basicLangChainExample() {
  const chain = await createBasicChain('anthropic');
  
  const result = await chain.invoke({
    question: "What are the benefits of renewable energy?"
  });
  
  console.log(result);
}

Advanced LangChain Patterns

// Multi-provider routing with LangChain
import { RouterChain } from '@langchain/core/chains';
import { LLMRouterChain, MultiPromptChain } from 'langchain/chains';
import { ConversationChain } from 'langchain/chains';

class LangChainProviderRouter {
  constructor() {
    this.providers = providers;
    this.setupRouterChains();
  }
  
  setupRouterChains() {
    // Define different chain types for different tasks
    this.chainConfigs = {
      reasoning: {
        provider: 'anthropic',
        prompt: PromptTemplate.fromTemplate(
          "Think step by step to answer: {input}"
        )
      },
      creative: {
        provider: 'openai',
        prompt: PromptTemplate.fromTemplate(
          "Be creative and engaging when answering: {input}"
        )
      },
      factual: {
        provider: 'google',
        prompt: PromptTemplate.fromTemplate(
          "Provide accurate, factual information about: {input}"
        )
      }
    };
  }
  
  async routeToOptimalChain(input, taskType = 'auto') {
    // Auto-detect task type if not specified
    if (taskType === 'auto') {
      taskType = await this.detectTaskType(input);
    }
    
    const config = this.chainConfigs[taskType] || this.chainConfigs['factual'];
    const model = this.providers[config.provider];
    
    const chain = RunnableSequence.from([
      config.prompt,
      model,
      new StringOutputParser()
    ]);
    
    return await chain.invoke({ input });
  }
  
  async detectTaskType(input) {
    // Simple keyword-based detection (could be enhanced with ML)
    const keywords = {
      reasoning: ['analyze', 'explain', 'why', 'how', 'because', 'logic'],
      creative: ['create', 'write', 'story', 'poem', 'creative', 'imagine'],
      factual: ['what', 'when', 'where', 'who', 'fact', 'data', 'statistics']
    };
    
    const inputLower = input.toLowerCase();
    const scores = {};
    
    for (const [type, words] of Object.entries(keywords)) {
      scores[type] = words.filter(word => inputLower.includes(word)).length;
    }
    
    return Object.entries(scores).reduce((a, b) => scores[a[0]] > scores[b[0]] ? a : b)[0];
  }
}

LangChain RAG Implementation

// RAG (Retrieval Augmented Generation) with LangChain
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
import { HNSWLib } from '@langchain/community/vectorstores/hnswlib';
import { OpenAIEmbeddings } from '@langchain/openai';
import { RetrievalQAChain } from 'langchain/chains';

class LangChainRAGSystem {
  constructor() {
    this.embeddings = new OpenAIEmbeddings({
      apiKey: process.env.OPENAI_API_KEY,
    });
    this.vectorStore = null;
    this.qaChain = null;
  }
  
  async setupRAG(documents) {
    // Split documents into chunks
    const textSplitter = new RecursiveCharacterTextSplitter({
      chunkSize: 1000,
      chunkOverlap: 200,
    });
    
    const splitDocs = await textSplitter.splitDocuments(documents);
    
    // Create vector store
    this.vectorStore = await HNSWLib.fromDocuments(
      splitDocs,
      this.embeddings
    );
    
    // Create QA chain with provider selection
    this.qaChain = RetrievalQAChain.fromLLM(
      providers.anthropic, // Use Claude for reasoning tasks
      this.vectorStore.asRetriever(3) // Retrieve top 3 relevant chunks
    );
  }
  
  async query(question, options = {}) {
    if (!this.qaChain) {
      throw new Error('RAG system not initialized. Call setupRAG first.');
    }
    
    const { provider = 'anthropic', includeSourceDocuments = true } = options;
    
    // Switch provider if requested
    if (provider !== 'anthropic') {
      this.qaChain = RetrievalQAChain.fromLLM(
        providers[provider],
        this.vectorStore.asRetriever(3)
      );
    }
    
    const result = await this.qaChain.call({
      query: question,
      return_source_documents: includeSourceDocuments
    });
    
    return {
      answer: result.text,
      sources: includeSourceDocuments ? result.sourceDocuments : []
    };
  }
  
  async addDocuments(newDocuments) {
    const textSplitter = new RecursiveCharacterTextSplitter({
      chunkSize: 1000,
      chunkOverlap: 200,
    });
    
    const splitDocs = await textSplitter.splitDocuments(newDocuments);
    await this.vectorStore.addDocuments(splitDocs);
  }
}

OpenRouter Integration

Setup and Configuration

// OpenRouter SDK setup and configuration
import OpenAI from 'openai';

class OpenRouterClient {
  constructor() {
    this.client = new OpenAI({
      baseURL: 'https://openrouter.ai/api/v1',
      apiKey: process.env.OPENROUTER_API_KEY,
      defaultHeaders: {
        'HTTP-Referer': process.env.YOUR_SITE_URL || 'http://localhost:3000',
        'X-Title': process.env.YOUR_APP_NAME || 'AI App',
      }
    });
    
    this.modelPricing = new Map();
    this.loadModelPricing();
  }
  
  async loadModelPricing() {
    try {
      // Fetch current model pricing from OpenRouter
      const response = await fetch('https://openrouter.ai/api/v1/models', {
        headers: {
          'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`
        }
      });
      
      const models = await response.json();
      
      models.data.forEach(model => {
        this.modelPricing.set(model.id, {
          prompt: parseFloat(model.pricing.prompt),
          completion: parseFloat(model.pricing.completion)
        });
      });
    } catch (error) {
      console.error('Failed to load OpenRouter pricing:', error);
    }
  }
  
  async complete(prompt, options = {}) {
    const {
      model = 'anthropic/claude-3.5-sonnet',
      maxTokens = 1000,
      temperature = 0.7,
      stream = false
    } = options;
    
    try {
      const response = await this.client.chat.completions.create({
        model: model,
        messages: [{ role: 'user', content: prompt }],
        max_tokens: maxTokens,
        temperature: temperature,
        stream: stream
      });
      
      return {
        text: response.choices[0].message.content,
        usage: response.usage,
        cost: this.calculateCost(response.usage, model),
        model: model
      };
    } catch (error) {
      console.error('OpenRouter API error:', error);
      throw error;
    }
  }
  
  calculateCost(usage, model) {
    const pricing = this.modelPricing.get(model);
    if (!pricing) return null;
    
    return (usage.prompt_tokens * pricing.prompt + 
            usage.completion_tokens * pricing.completion) / 1000000;
  }
}

OpenRouter Model Selection and Optimization

// Advanced OpenRouter features
class OptimizedOpenRouter extends OpenRouterClient {
  constructor() {
    super();
    this.modelPerformance = new Map();
    this.setupModelCategories();
  }
  
  setupModelCategories() {
    // Categorize models by use case and performance characteristics
    this.modelCategories = {
      'fast-cheap': [
        'meta-llama/llama-3.1-8b-instruct:free',
        'microsoft/wizardlm-2-8x22b',
        'google/gemma-7b-it:free'
      ],
      'balanced': [
        'anthropic/claude-3.5-sonnet',
        'openai/gpt-4o-mini',
        'google/gemini-pro'
      ],
      'premium': [
        'openai/gpt-4o',
        'anthropic/claude-3-opus',
        'google/gemini-pro-1.5'
      ],
      'coding': [
        'anthropic/claude-3.5-sonnet',
        'openai/gpt-4o',
        'deepseek/deepseek-coder'
      ],
      'reasoning': [
        'anthropic/claude-3.5-sonnet',
        'openai/o1-preview',
        'openai/gpt-4o'
      ]
    };
  }
  
  async selectOptimalModel(prompt, requirements = {}) {
    const {
      budget = 'balanced',
      taskType = 'general',
      maxLatency = 10000,
      minQuality = 0.7
    } = requirements;
    
    let candidateModels = this.modelCategories[budget] || this.modelCategories['balanced'];
    
    // Filter by task type if specified
    if (taskType !== 'general' && this.modelCategories[taskType]) {
      candidateModels = this.modelCategories[taskType];
    }
    
    // Score models based on historical performance
    const scoredModels = candidateModels.map(model => ({
      model,
      score: this.calculateModelScore(model, requirements)
    }));
    
    // Sort by score and return best model
    scoredModels.sort((a, b) => b.score - a.score);
    return scoredModels[0].model;
  }
  
  calculateModelScore(model, requirements) {
    const performance = this.modelPerformance.get(model) || {
      avgLatency: 3000,
      avgQuality: 0.8,
      avgCost: 0.001
    };
    
    let score = 0;
    
    // Latency score (lower is better)
    if (performance.avgLatency <= requirements.maxLatency) {
      score += (requirements.maxLatency - performance.avgLatency) / requirements.maxLatency * 30;
    }
    
    // Quality score
    if (performance.avgQuality >= requirements.minQuality) {
      score += performance.avgQuality * 40;
    }
    
    // Cost efficiency score (lower cost is better)
    score += (1 - Math.min(performance.avgCost / 0.01, 1)) * 20;
    
    // Model availability score
    score += 10; // Base availability score
    
    return score;
  }
  
  async completeWithOptimalModel(prompt, requirements = {}) {
    const selectedModel = await this.selectOptimalModel(prompt, requirements);
    
    console.log(`Selected model: ${selectedModel}`);
    
    const startTime = Date.now();
    const result = await this.complete(prompt, { 
      model: selectedModel,
      ...requirements 
    });
    const endTime = Date.now();
    
    // Update performance metrics
    this.updateModelPerformance(selectedModel, {
      latency: endTime - startTime,
      cost: result.cost
    });
    
    return {
      ...result,
      selectedModel,
      latency: endTime - startTime
    };
  }
  
  updateModelPerformance(model, metrics) {
    const current = this.modelPerformance.get(model) || {
      avgLatency: 3000,
      avgQuality: 0.8,
      avgCost: 0.001,
      samples: 0
    };
    
    const samples = current.samples + 1;
    const alpha = 1 / Math.min(samples, 100); // Exponential moving average
    
    this.modelPerformance.set(model, {
      avgLatency: current.avgLatency * (1 - alpha) + metrics.latency * alpha,
      avgCost: current.avgCost * (1 - alpha) + metrics.cost * alpha,
      avgQuality: current.avgQuality, // Quality would need separate evaluation
      samples
    });
  }
}

OpenRouter Streaming and Fallbacks

// Streaming and fallback implementation
class RobustOpenRouter extends OptimizedOpenRouter {
  constructor() {
    super();
    this.fallbackModels = new Map();
    this.setupFallbacks();
  }
  
  setupFallbacks() {
    // Define fallback chains for different model categories
    this.fallbackModels.set('anthropic/claude-3.5-sonnet', [
      'openai/gpt-4o-mini',
      'google/gemini-pro',
      'meta-llama/llama-3.1-70b-instruct'
    ]);
    
    this.fallbackModels.set('openai/gpt-4o', [
      'anthropic/claude-3.5-sonnet',
      'openai/gpt-4o-mini',
      'google/gemini-pro'
    ]);
  }
  
  async completeWithFallback(prompt, options = {}) {
    const primaryModel = await this.selectOptimalModel(prompt, options);
    const fallbacks = this.fallbackModels.get(primaryModel) || [];
    const modelsToTry = [primaryModel, ...fallbacks];
    
    for (const model of modelsToTry) {
      try {
        return await this.complete(prompt, { ...options, model });
      } catch (error) {
        console.warn(`Model ${model} failed: ${error.message}`);
        
        // If this was the last model, throw the error
        if (model === modelsToTry[modelsToTry.length - 1]) {
          throw new Error(`All models failed. Last error: ${error.message}`);
        }
        
        continue;
      }
    }
  }
  
  async streamWithFallback(prompt, options = {}) {
    const primaryModel = await this.selectOptimalModel(prompt, options);
    
    try {
      const stream = await this.client.chat.completions.create({
        model: primaryModel,
        messages: [{ role: 'user', content: prompt }],
        stream: true,
        ...options
      });
      
      return this.processStream(stream);
    } catch (error) {
      console.warn(`Streaming with ${primaryModel} failed, falling back to regular completion`);
      return await this.completeWithFallback(prompt, options);
    }
  }
  
  async *processStream(stream) {
    try {
      for await (const chunk of stream) {
        const content = chunk.choices[0]?.delta?.content || '';
        if (content) {
          yield content;
        }
      }
    } catch (error) {
      console.error('Stream processing error:', error);
      throw error;
    }
  }
}

Together AI Integration

Setup and Model Management

// Together AI integration
import Together from 'together-ai';

class TogetherAIProvider {
  constructor() {
    this.client = new Together({
      apiKey: process.env.TOGETHER_API_KEY,
    });
    this.availableModels = new Map();
    this.loadAvailableModels();
  }
  
  async loadAvailableModels() {
    try {
      const models = await this.client.models.list();
      
      models.forEach(model => {
        this.availableModels.set(model.id, {
          name: model.display_name,
          type: model.type,
          context_length: model.context_length,
          pricing: model.pricing
        });
      });
      
      console.log(`Loaded ${this.availableModels.size} Together AI models`);
    } catch (error) {
      console.error('Failed to load Together AI models:', error);
    }
  }
  
  async complete(prompt, options = {}) {
    const {
      model = 'meta-llama/Llama-2-70b-chat-hf',
      maxTokens = 1000,
      temperature = 0.7,
      systemPrompt = null
    } = options;
    
    const messages = [];
    
    if (systemPrompt) {
      messages.push({ role: 'system', content: systemPrompt });
    }
    
    messages.push({ role: 'user', content: prompt });
    
    try {
      const response = await this.client.chat.completions.create({
        model: model,
        messages: messages,
        max_tokens: maxTokens,
        temperature: temperature,
      });
      
      return {
        text: response.choices[0].message.content,
        usage: response.usage,
        cost: this.calculateCost(response.usage, model),
        model: model
      };
    } catch (error) {
      console.error('Together AI error:', error);
      throw error;
    }
  }
  
  calculateCost(usage, model) {
    const modelInfo = this.availableModels.get(model);
    if (!modelInfo || !modelInfo.pricing) return null;
    
    const inputCost = usage.prompt_tokens * modelInfo.pricing.input / 1000000;
    const outputCost = usage.completion_tokens * modelInfo.pricing.output / 1000000;
    
    return inputCost + outputCost;
  }
  
  getModelsByType(type = 'chat') {
    return Array.from(this.availableModels.entries())
      .filter(([_, info]) => info.type === type)
      .map(([id, info]) => ({ id, ...info }));
  }
  
  getOpenSourceModels() {
    // Together AI specializes in open source models
    const openSourceKeywords = ['llama', 'mistral', 'falcon', 'vicuna', 'alpaca'];
    
    return Array.from(this.availableModels.entries())
      .filter(([id, _]) => 
        openSourceKeywords.some(keyword => 
          id.toLowerCase().includes(keyword)
        )
      )
      .map(([id, info]) => ({ id, ...info }));
  }
}

Together AI Fine-tuning Integration

// Fine-tuning capabilities with Together AI
class TogetherAIFineTuning extends TogetherAIProvider {
  constructor() {
    super();
    this.finetunes = new Map();
  }
  
  async createFineTune(trainingData, options = {}) {
    const {
      baseModel = 'meta-llama/Llama-2-7b-chat-hf',
      suffix = 'custom-model',
      learningRate = 1e-5,
      epochs = 3,
      batchSize = 1
    } = options;
    
    try {
      // Upload training data
      const file = await this.client.files.upload({
        file: trainingData,
        purpose: 'fine-tune'
      });
      
      // Create fine-tuning job
      const fineTune = await this.client.fineTuning.jobs.create({
        training_file: file.id,
        model: baseModel,
        suffix: suffix,
        hyperparameters: {
          learning_rate_multiplier: learningRate,
          n_epochs: epochs,
          batch_size: batchSize
        }
      });
      
      this.finetunes.set(fineTune.id, fineTune);
      
      console.log(`Fine-tuning job created: ${fineTune.id}`);
      return fineTune;
    } catch (error) {
      console.error('Fine-tuning creation failed:', error);
      throw error;
    }
  }
  
  async checkFineTuneStatus(fineTuneId) {
    try {
      const fineTune = await this.client.fineTuning.jobs.retrieve(fineTuneId);
      this.finetunes.set(fineTuneId, fineTune);
      
      return {
        id: fineTune.id,
        status: fineTune.status,
        model: fineTune.fine_tuned_model,
        progress: fineTune.progress || 0
      };
    } catch (error) {
      console.error('Failed to check fine-tune status:', error);
      throw error;
    }
  }
  
  async useFineTunedModel(prompt, fineTunedModelId, options = {}) {
    return await this.complete(prompt, {
      model: fineTunedModelId,
      ...options
    });
  }
  
  async listFineTunes() {
    try {
      const fineTunes = await this.client.fineTuning.jobs.list();
      return fineTunes.data;
    } catch (error) {
      console.error('Failed to list fine-tunes:', error);
      throw error;
    }
  }
}

Custom Provider Solutions

Building a Custom Provider Interface

// Custom provider abstraction layer
class CustomProviderInterface {
  constructor() {
    this.providers = new Map();
    this.middleware = [];
    this.metrics = new Map();
  }
  
  registerProvider(name, provider) {
    if (!provider.complete) {
      throw new Error('Provider must implement complete() method');
    }
    
    this.providers.set(name, {
      instance: provider,
      config: provider.config || {},
      metrics: {
        requests: 0,
        errors: 0,
        totalCost: 0,
        avgLatency: 0
      }
    });
  }
  
  addMiddleware(middleware) {
    this.middleware.push(middleware);
  }
  
  async complete(prompt, options = {}) {
    const { provider = 'default', ...providerOptions } = options;
    
    if (!this.providers.has(provider)) {
      throw new Error(`Provider ${provider} not registered`);
    }
    
    const providerInfo = this.providers.get(provider);
    
    // Apply middleware
    let context = {
      prompt,
      options: providerOptions,
      provider,
      startTime: Date.now()
    };
    
    for (const mw of this.middleware) {
      context = await mw.before(context);
    }
    
    try {
      // Execute provider
      const result = await providerInfo.instance.complete(
        context.prompt,
        context.options
      );
      
      context.result = result;
      context.endTime = Date.now();
      
      // Apply post-middleware
      for (const mw of this.middleware.reverse()) {
        if (mw.after) {
          context = await mw.after(context);
        }
      }
      
      // Update metrics
      this.updateMetrics(provider, context);
      
      return context.result;
    } catch (error) {
      // Update error metrics
      providerInfo.metrics.errors++;
      
      // Apply error middleware
      for (const mw of this.middleware.reverse()) {
        if (mw.error) {
          await mw.error(context, error);
        }
      }
      
      throw error;
    }
  }
  
  updateMetrics(provider, context) {
    const providerInfo = this.providers.get(provider);
    const metrics = providerInfo.metrics;
    
    metrics.requests++;
    
    if (context.result.cost) {
      metrics.totalCost += context.result.cost;
    }
    
    const latency = context.endTime - context.startTime;
    metrics.avgLatency = (metrics.avgLatency * (metrics.requests - 1) + latency) / metrics.requests;
  }
  
  getMetrics(provider = null) {
    if (provider) {
      return this.providers.get(provider)?.metrics;
    }
    
    const allMetrics = {};
    for (const [name, info] of this.providers.entries()) {
      allMetrics[name] = info.metrics;
    }
    return allMetrics;
  }
}

Middleware Examples

// Useful middleware implementations
class CachingMiddleware {
  constructor(ttl = 3600000) { // 1 hour default
    this.cache = new Map();
    this.ttl = ttl;
  }
  
  async before(context) {
    const cacheKey = this.generateCacheKey(context.prompt, context.options);
    const cached = this.cache.get(cacheKey);
    
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      context.result = cached.result;
      context.fromCache = true;
      throw new CacheHitException(cached.result);
    }
    
    return context;
  }
  
  async after(context) {
    if (!context.fromCache) {
      const cacheKey = this.generateCacheKey(context.prompt, context.options);
      this.cache.set(cacheKey, {
        result: context.result,
        timestamp: Date.now()
      });
    }
    
    return context;
  }
  
  generateCacheKey(prompt, options) {
    return `${prompt}_${JSON.stringify(options)}`;
  }
}

class CostTrackingMiddleware {
  constructor() {
    this.dailyCosts = new Map();
    this.limits = new Map();
  }
  
  setDailyLimit(provider, limit) {
    this.limits.set(provider, limit);
  }
  
  async before(context) {
    const today = new Date().toISOString().split('T')[0];
    const key = `${context.provider}_${today}`;
    
    const dailyCost = this.dailyCosts.get(key) || 0;
    const limit = this.limits.get(context.provider);
    
    if (limit && dailyCost >= limit) {
      throw new Error(`Daily cost limit exceeded for ${context.provider}`);
    }
    
    return context;
  }
  
  async after(context) {
    if (context.result.cost) {
      const today = new Date().toISOString().split('T')[0];
      const key = `${context.provider}_${today}`;
      
      const currentCost = this.dailyCosts.get(key) || 0;
      this.dailyCosts.set(key, currentCost + context.result.cost);
    }
    
    return context;
  }
  
  getDailyCost(provider, date = null) {
    const dateStr = date || new Date().toISOString().split('T')[0];
    const key = `${provider}_${dateStr}`;
    return this.dailyCosts.get(key) || 0;
  }
}

class RetryMiddleware {
  constructor(maxRetries = 3, baseDelay = 1000) {
    this.maxRetries = maxRetries;
    this.baseDelay = baseDelay;
  }
  
  async error(context, error) {
    const retryCount = context.retryCount || 0;
    
    if (retryCount < this.maxRetries && this.isRetryableError(error)) {
      context.retryCount = retryCount + 1;
      
      const delay = this.baseDelay * Math.pow(2, retryCount);
      await new Promise(resolve => setTimeout(resolve, delay));
      
      // Retry the request
      return await this.retry(context);
    }
    
    throw error;
  }
  
  isRetryableError(error) {
    const retryableMessages = [
      'rate limit',
      'timeout',
      'service unavailable',
      'internal server error'
    ];
    
    return retryableMessages.some(msg => 
      error.message.toLowerCase().includes(msg)
    );
  }
  
  async retry(context) {
    // This would need to be handled by the main provider interface
    throw new RetryException(context);
  }
}

Complete Integration Example

Unified Framework Manager

// Complete integration bringing everything together
class UnifiedFrameworkManager {
  constructor() {
    this.customProvider = new CustomProviderInterface();
    this.langchainRouter = new LangChainProviderRouter();
    this.openRouter = new RobustOpenRouter();
    this.togetherAI = new TogetherAIFineTuning();
    
    this.setupMiddleware();
    this.registerProviders();
  }
  
  setupMiddleware() {
    // Add middleware to custom provider
    this.customProvider.addMiddleware(new CachingMiddleware(3600000));
    this.customProvider.addMiddleware(new CostTrackingMiddleware());
    this.customProvider.addMiddleware(new RetryMiddleware(3, 1000));
  }
  
  registerProviders() {
    // Register all providers with the custom interface
    this.customProvider.registerProvider('langchain', {
      complete: async (prompt, options) => {
        return await this.langchainRouter.routeToOptimalChain(prompt, options.taskType);
      },
      config: { type: 'orchestration' }
    });
    
    this.customProvider.registerProvider('openrouter', {
      complete: async (prompt, options) => {
        return await this.openRouter.completeWithOptimalModel(prompt, options);
      },
      config: { type: 'gateway' }
    });
    
    this.customProvider.registerProvider('together', {
      complete: async (prompt, options) => {
        return await this.togetherAI.complete(prompt, options);
      },
      config: { type: 'hosting' }
    });
  }
  
  async intelligentComplete(prompt, requirements = {}) {
    const {
      taskType = 'general',
      budget = 'balanced',
      latencyRequirement = 'medium',
      qualityRequirement = 'high'
    } = requirements;
    
    // Select optimal framework based on requirements
    const framework = this.selectFramework(requirements);
    
    console.log(`Selected framework: ${framework}`);
    
    try {
      return await this.customProvider.complete(prompt, {
        provider: framework,
        taskType,
        budget,
        ...requirements
      });
    } catch (error) {
      console.error(`Framework ${framework} failed, trying fallback`);
      
      // Try fallback framework
      const fallback = this.getFallbackFramework(framework);
      return await this.customProvider.complete(prompt, {
        provider: fallback,
        taskType,
        budget,
        ...requirements
      });
    }
  }
  
  selectFramework(requirements) {
    const { taskType, budget, latencyRequirement } = requirements;
    
    // Decision matrix for framework selection
    if (taskType === 'rag' || taskType === 'complex-workflow') {
      return 'langchain';
    }
    
    if (budget === 'premium' && latencyRequirement === 'low') {
      return 'openrouter';
    }
    
    if (budget === 'minimal' || taskType === 'open-source') {
      return 'together';
    }
    
    // Default to OpenRouter for balanced needs
    return 'openrouter';
  }
  
  getFallbackFramework(primary) {
    const fallbacks = {
      'langchain': 'openrouter',
      'openrouter': 'together',
      'together': 'langchain'
    };
    
    return fallbacks[primary] || 'openrouter';
  }
  
  async getFrameworkMetrics() {
    return {
      custom: this.customProvider.getMetrics(),
      frameworks: {
        langchain: 'Available',
        openrouter: 'Available',
        together: 'Available'
      }
    };
  }
}

// Usage example
async function demonstrateFrameworkIntegration() {
  const manager = new UnifiedFrameworkManager();
  
  // Example 1: Complex reasoning task
  const reasoningResult = await manager.intelligentComplete(
    "Analyze the potential economic impacts of widespread AI adoption",
    {
      taskType: 'reasoning',
      budget: 'premium',
      qualityRequirement: 'highest'
    }
  );
  
  console.log('Reasoning Result:', reasoningResult.text.substring(0, 200) + '...');
  
  // Example 2: Cost-optimized simple task
  const simpleResult = await manager.intelligentComplete(
    "Summarize this text in one sentence",
    {
      taskType: 'general',
      budget: 'minimal',
      latencyRequirement: 'low'
    }
  );
  
  console.log('Simple Result:', simpleResult.text);
  
  // View metrics
  const metrics = await manager.getFrameworkMetrics();
  console.log('Framework Metrics:', metrics);
}

Best Practices

Framework Selection Guidelines

  1. LangChain: Use for complex workflows, RAG systems, and when you need extensive ecosystem integration
  2. OpenRouter: Use for model experimentation, unified API access, and when you need automatic model routing
  3. Together AI: Use for open-source models, custom fine-tuning, and cost-optimized inference
  4. Custom Solutions: Use when you need specific optimizations or have unique requirements

Performance Optimization

  1. Caching: Implement response caching to reduce API calls
  2. Batching: Group similar requests when possible
  3. Model Selection: Use appropriate models for each task type
  4. Monitoring: Track performance metrics across all frameworks

Cost Management

  1. Budget Controls: Implement spending limits per framework
  2. Model Optimization: Use cheaper models for simpler tasks
  3. Usage Tracking: Monitor usage patterns to identify optimization opportunities
  4. Fallback Strategies: Implement cost-aware fallback mechanisms

Conclusion

Development framework integration requires understanding each framework’s strengths and implementing intelligent routing between them. By using the patterns and implementations in this guide, you can build a robust system that leverages the best features of multiple frameworks while maintaining cost efficiency and performance.

Start with one framework that matches your primary use case, then gradually integrate others as your needs expand. Always implement proper monitoring and fallback strategies to ensure reliability across your entire AI infrastructure.

← Back to Learning Center