How to Add a New LLM Adapter for a Custom Provider in TradingAgents-CN

To add a new LLM adapter for a custom provider in TradingAgents-CN, create a Python module in tradingagents/llm_adapters/, subclass a LangChain base class such as ChatOpenAI, implement __init__ for API key resolution, override _generate for token tracking, and export the class from tradingagents/llm_adapters/__init__.py.

The TradingAgents-CN repository isolates every large language model behind a standardized adapter interface, allowing seamless swapping between providers like DashScope and Google without changing business logic. When you need to integrate a proprietary or niche LLM service, you must add a new LLM adapter for a custom provider in TradingAgents-CN following the canonical five-component pattern established in the codebase. This guide walks through the exact file locations, method signatures, and token-tracking requirements derived from the reference implementations.

Understanding the Adapter Architecture in TradingAgents-CN

Every LLM adapter in TradingAgents-CN follows a strict five-component contract to ensure consistent behavior across providers. Located in tradingagents/llm_adapters/, each module subclasses a LangChain base—typically ChatOpenAI for OpenAI-compatible endpoints—and implements provider-specific initialization, token tracking, and factory utilities.

The five mandatory components are:

  • Base class inheritance – Subclass ChatOpenAI (or another LangChain chat model) to inherit standard invocation patterns.
  • Initialization logic – Resolve API keys from database configuration or environment variables, set sensible defaults for temperature, max_tokens, and base_url, and validate credentials.
  • Token tracking – Override _generate to intercept usage statistics and forward them to the central token_tracker from tradingagents.config.config_manager.
  • Factory helpers – Provide create_<provider>_llm, get_available_<provider>_models, and optional test_* functions for quick instantiation and validation.
  • Module export – Register the adapter in tradingagents/llm_adapters/__init__.py so it is importable as from tradingagents.llm_adapters import ChatMyProvider.

Reference implementations demonstrate this pattern clearly. In tradingagents/llm_adapters/dashscope_openai_adapter.py, the class header and inheritance appear at lines 19–20, the __init__ method handling API key resolution and defaults spans lines 28–79, and the token-tracking _generate override occupies lines 102–136.

Step-by-Step Guide to Adding Your Custom LLM Adapter

Step 1: Create the Adapter Module

Create a new Python file at tradingagents/llm_adapters/myprovider_adapter.py. This file will house the adapter class and all supporting utilities for your custom provider.

Step 2: Import Core Dependencies

At the top of the module, import the required LangChain classes, typing utilities, and TradingAgents-CN internals:

import os
from typing import Any, Dict, List, Optional

from langchain_openai import ChatOpenAI
from langchain_core.tools import BaseTool

from tradingagents.utils.logging_manager import get_logger
from tradingagents.config.config_manager import token_tracker

Step 3: Define the Adapter Class

Subclass ChatOpenAI (or the appropriate LangChain base for your provider) and provide a docstring:

class ChatMyProvider(ChatOpenAI):
    """MyProvider OpenAI-compatible adapter with token tracking."""

Step 4: Implement Initialization and Configuration

Override __init__ to handle provider-specific setup. Follow the pattern from dashscope_openai_adapter.py lines 28–79:

  • Log initialization start using get_logger(__name__).
  • Resolve the API key from kwargs or the MYPROVIDER_API_KEY environment variable.
  • Set defaults for base_url, model, temperature, and max_tokens using kwargs.setdefault(...).
  • Validate the API key and raise ValueError if missing.
  • Call super().__init__(**kwargs) to complete LangChain initialization.

Step 5: Add Token Tracking

Override the _generate method to intercept usage statistics and forward them to the central tracker, mirroring lines 102–136 of the DashScope adapter:

def _generate(self, messages, stop=None, run_manager=None, **kwargs):
    result = super()._generate(messages, stop=run_manager, **kwargs)
    
    if result.llm_output and "token_usage" in result.llm_output:
        usage = result.llm_output["token_usage"]
        session_id = kwargs.get("session_id", "default")
        analysis_type = kwargs.get("analysis_type", "general")
        
        token_tracker.track_usage(
            provider="myprovider",
            model=self.model_name,
            input_tokens=usage.get("prompt_tokens", 0),
            output_tokens=usage.get("completion_tokens", 0),
            session_id=session_id,
            analysis_type=analysis_type
        )
    
    return result

Step 6: Define Model Metadata and Factory Helpers

Create a dictionary mapping model names to capabilities, then provide a factory function:

MYPROVIDER_MODELS = {
    "my-model": {
        "description": "MyProvider standard model",
        "context_length": 8192,
        "supports_function_calling": True,
        "recommended_for": ["analysis", "trading"]
    }
}

def create_myprovider_llm(
    model: str = "my-model",
    api_key: Optional[str] = None,
    temperature: float = 0.1,
    max_tokens: int = 2000,
    **kwargs
) -> ChatMyProvider:
    """Factory function to instantiate MyProvider LLM."""
    return ChatMyProvider(
        model=model,
        api_key=api_key,
        temperature=temperature,
        max_tokens=max_tokens,
        **kwargs
    )

def get_available_myprovider_models() -> Dict[str, Any]:
    """Return metadata for available MyProvider models."""
    return MYPROVIDER_MODELS

Step 7: Register the Adapter

Open tradingagents/llm_adapters/__init__.py and add the import:

from .myprovider_adapter import ChatMyProvider

__all__.append("ChatMyProvider")

This makes the adapter available via from tradingagents.llm_adapters import ChatMyProvider.

Complete Working Example

Here is a minimal, runnable example demonstrating how to use the newly created adapter once registered:


# example_usage.py

from tradingagents.llm_adapters import ChatMyProvider

# 1️⃣ Create an LLM instance (API key can be omitted if set in env var MYPROVIDER_API_KEY)

llm = ChatMyProvider(
    model="my-model",
    temperature=0.2,
    max_tokens=500,
    # You can also pass a custom endpoint:

    # base_url="https://api.myprovider.com/v1"

)

# 2️⃣ Simple invoke

response = llm.invoke("请介绍一下今天的AAPL股价走势。")
print("模型回复:", response.content)

# 3️⃣ Function‑calling example (assuming the provider supports it)

from langchain_core.tools import tool

@tool
def get_stock_price(symbol: str) -> str:
    """返回给定股票代码的当前价格(模拟实现)。"""
    return f"{symbol} 当前价: 123.45 USD"

llm_with_tool = llm.bind_tools([get_stock_price])
result = llm_with_tool.invoke("请帮我查询下 AAPL 的最新价格")
print(result)          # May contain `tool_calls` if the model decides to use the tool

Running this script logs initialization steps via the adapter's logger, automatically tracks token usage through token_tracker, and allows seamless provider swapping by changing only the import line.

Key Reference Files and Implementation Details

Study these specific files and line ranges to understand the exact implementation patterns:

File Purpose Critical Sections
tradingagents/llm_adapters/__init__.py Public export of adapters Lines 1‑5 demonstrate how adapters are re-exported for clean imports
tradingagents/llm_adapters/dashscope_openai_adapter.py Reference for OpenAI-compatible providers Inheritance (lines 19‑20)__init__ with API key handling (lines 28‑79)Token tracking in _generate (lines 102‑136)
tradingagents/llm_adapters/google_openai_adapter.py Reference for non-OpenAI providers Custom base class handling and base_url configuration (lines 21‑38)
tradingagents/config/config_manager.py Central token tracking infrastructure Provides token_tracker used by all adapters for usage analytics

Summary

To successfully add a new LLM adapter for a custom provider in TradingAgents-CN, follow these core principles:

  • Isolate provider logic in a dedicated module under tradingagents/llm_adapters/ using the five-component structure.
  • Inherit from LangChain bases like ChatOpenAI to maintain compatibility with the existing tool-calling and invocation patterns.
  • Validate credentials early in __init__, supporting both explicit arguments and environment variables with clear error messages.
  • Track every token by overriding _generate and forwarding usage statistics to token_tracker from tradingagents.config.config_manager.
  • Expose clean factory functions like create_myprovider_llm and register the class in tradingagents/llm_adapters/__init__.py for discoverability.

Frequently Asked Questions

What base class should I use when adding a new LLM adapter for a custom provider in TradingAgents-CN?

Use ChatOpenAI from langchain_openai if your provider offers an OpenAI-compatible API. For providers with unique protocols, subclass the appropriate LangChain class (such as ChatGoogleGenerativeAI for Google models) and normalize the interface within your adapter. The existing google_openai_adapter.py demonstrates how to handle non-OpenAI bases while maintaining compatibility.

How does token tracking work in custom TradingAgents-CN LLM adapters?

Token tracking relies on overriding the _generate method in your adapter class. After calling super()._generate(), inspect result.llm_output["token_usage"] to extract prompt_tokens and completion_tokens. Forward these values along with the provider name and model identifier to token_tracker.track_usage() from tradingagents.config.config_manager. This pattern appears in dashscope_openai_adapter.py lines 102–136.

Where should I store API keys for a custom LLM provider in TradingAgents-CN?

Resolve API keys using a cascading priority: first check the api_key argument passed to __init__, then fall back to environment variables (e.g., MYPROVIDER_API_KEY), and optionally check the database configuration if your adapter integrates with the project's config manager. Always validate the key exists before calling super().__init__() and raise a descriptive ValueError if credentials are missing, following the validation logic in dashscope_openai_adapter.py lines 34–68.

Can I use function calling and tools with a custom LLM adapter in TradingAgents-CN?

Yes, provided your underlying provider supports function calling. Inherit from ChatOpenAI (which supports tool binding) and ensure your model metadata dictionary includes "supports_function_calling": True. Users can then call llm.bind_tools([...]) and invoke the model with tool definitions. Test this capability by implementing a test_myprovider_function_calling helper function in your adapter module, following the validation patterns in existing adapters.

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 →