Run FinRobot on a custom OpenAI-compatible endpoint.

Updated 2026-07-16

FinRobot reads its LLM credentials from an AutoGen OAI_CONFIG_LIST file whose entries accept a base_url key. Add one entry pointing at https://api.apisrouter.com/v1 with a gateway key, and the forecaster, report-writer, and RAG agents can run on any model id in the catalog.

Quick answer: one entry in OAI_CONFIG_LIST.

FinRobot's setup instructions have you rename OAI_CONFIG_LIST_sample to OAI_CONFIG_LIST and fill in credentials. That file is a standard AutoGen config list: a JSON array where each entry takes model and api_key, and optionally base_url, which the shipped sample already demonstrates for non-default endpoints. Add an entry with your gateway key and base_url set to https://api.apisrouter.com/v1, and every FinRobot agent that loads the file can route through it. One catch that costs people time: the tutorials load the file through autogen.config_list_from_json with a filter_dict that selects entries by model name. If your new entry says claude-sonnet-4-6 but the filter still asks for the sample's GPT id, your entry is filtered out and the run fails on the old credentials. Update the filter_dict to match the model you added, or drop the filter while testing.

[
    {
        "model": "claude-sonnet-4-6",
        "api_key": "sk-YOUR-APISROUTER-KEY",
        "base_url": "https://api.apisrouter.com/v1"
    }
]

How FinRobot uses its LLM config.

FinRobot (AI4Finance-Foundation on GitHub, roughly 7.6K stars) is an AI agent platform for financial analysis built on AutoGen (pyautogen 0.2.19 or newer). Its agents are packaged workflows: a Market_Analyst forecaster that pulls company news and fundamentals and predicts next-week movement, an annual-report writer that turns filings into an equity research PDF, and retrieval-augmented QA agents over earnings calls and SEC filings. Each tutorial builds the same llm_config shape: a dict whose config_list comes from autogen.config_list_from_json reading the OAI_CONFIG_LIST file. That llm_config is handed to wrapper classes like SingleAssistant and SingleAssistantShadow from finrobot.agents.workflow, which own the underlying AutoGen agents. The endpoint decision therefore lives entirely in the JSON file: AutoGen's OpenAI client sends /v1/chat/completions requests to whatever base_url the selected entry carries and forwards the model field as a plain string. That plain string is the practical win. When the endpoint behind base_url serves multiple vendors, a Claude, DeepSeek, or Qwen id rides through the same OpenAI-shaped config without FinRobot noticing, and swapping the analysis model becomes a one-line JSON edit plus a matching filter_dict.

Full setup: config file, filter, and data keys.

FinRobot splits credentials across two files, and only one of them concerns the LLM. OAI_CONFIG_LIST holds model endpoints and keys. config_api_keys holds market-data credentials (FINNHUB_API_KEY, FMP_API_KEY, SEC_API_KEY, and social keys), loaded separately through register_keys_from_json. Routing the LLM through a gateway changes the first file and leaves the second alone, so news pulls, fundamentals, and filings behave exactly as before. The tutorial pattern below is the forecaster notebook's structure with the gateway entry selected. The same llm_config works for the annual-report and RAG tutorials, which differ only in which workflow class they instantiate.

import autogen
from finrobot.utils import register_keys_from_json
from finrobot.agents.workflow import SingleAssistant

llm_config = {
    "config_list": autogen.config_list_from_json(
        "../OAI_CONFIG_LIST",
        filter_dict={"model": ["claude-sonnet-4-6"]},  # match your entry
    ),
    "timeout": 120,
    "temperature": 0,
}

register_keys_from_json("../config_api_keys")  # finnhub/fmp/sec data keys

assistant = SingleAssistant("Market_Analyst", llm_config,
                            human_input_mode="NEVER")
assistant.chat("Analyze NVDA news this week and predict next week's movement.")

Choosing models per FinRobot workflow.

The clean experiment loop: fix the ticker and date range, run the same workflow once per candidate entry, and compare outputs side by side. Behind one endpoint each candidate is a filter_dict edit, and the per-key usage log gives you the token bill per candidate without spreadsheet work.

  • The annual-report writer is the heaviest reasoning job: it reads filing sections, synthesizes an investment thesis, and drafts a structured report. claude-opus-4-7 or gpt-5.5 in that workflow is where output quality visibly changes.
  • The market forecaster is a shorter, repeated task over news and fundamentals. claude-sonnet-4-6 or deepseek-v4-pro handles it well, and matters when you run it across a watchlist daily.
  • RAG QA over earnings calls is retrieval plus synthesis over long excerpts, which favors long-context ids; gemini-3.1-pro-preview is worth testing against claude-sonnet-4-6 there.
  • Because entries are selected by filter_dict, you can keep one file with a frontier entry and a fast entry against the same base_url and pick per notebook, rather than editing credentials per run.
  • Model ids are exact strings. FinRobot passes them through unvalidated, so the /v1/models listing of the endpoint is the authoritative spelling.

Pay-as-you-go · transparent per-model pricing

Selected models are priced below official list prices. Exact input, output, cache, and per-request prices are shown for each model.

ModelOfficial PriceOur Price
Claude Opus 4.7$5.00 / $25.00 per M$4.00 / $20.00 per M
Claude Sonnet 4.6$3.00 / $15.00 per M$2.40 / $12.00 per M
GPT-5.4$2.50 / $15.00 per M$2.00 / $12.00 per M
DeepSeek V4 Pro$0.43 / $0.87 per M$0.39 / $0.78 per M
Gemini 3.1 Pro Preview$2.00 / $12.00 per M$1.60 / $9.60 per M

Failure modes specific to FinRobot.

The filter_dict mismatch is the big one. config_list_from_json returns only entries whose model matches the filter; a filter that matches nothing raises an error about an empty config list, and a filter that matches the sample's leftover entries sends requests to OpenAI with placeholder keys, which surfaces as a 401 from the wrong host. When routing changes do not seem to take effect, print the resolved config_list first. Relative paths are the second. The tutorials load "../OAI_CONFIG_LIST" because notebooks sit one level below the repo root; a script at the root wants "OAI_CONFIG_LIST" instead, and AutoGen also accepts the OAI_CONFIG_LIST environment variable carrying the JSON string, which sidesteps path issues in containers. Comment lines are the third. The setup instructions tell you to remove the comment notes from the sample files because they make the JSON invalid; a JSONDecodeError on startup means a stray comment survived. Data credentials fail independently. If the agent chats fine but news or fundamentals come back empty, that is a config_api_keys problem (Finnhub, FMP, SEC), not an endpoint problem. And the separate FinRobot Pro equity module configures its keys through a config.ini instead; as of July 2026 its documented settings cover an openai_api_key but no base-URL override, so treat that module as direct-vendor until upstream documents one.

Who routes FinRobot through a gateway.

  • Analysts generating equity reports across a coverage list. Long filing contexts per report make per-model price differences material, and one endpoint makes the model a per-run choice.
  • Quant teams running the forecaster daily over a watchlist, where a fast mid-tier id keeps the recurring bill flat without rewriting the workflow.
  • Researchers comparing model families on identical financial tasks. Each candidate is one config entry, not a vendor account and SDK swap.
  • Teams standardizing AutoGen-based stacks. FinRobot shares the OAI_CONFIG_LIST convention with other AutoGen projects, so one gateway entry format serves all of them.
  • Developers without access to a given vendor's billing. Top-up based access with no card requirement removes the per-provider sign-up dependency.

Verify the endpoint and debug the first run.

List the models your key can address before opening a notebook; every model string in OAI_CONFIG_LIST and every filter_dict value must match a served id exactly. Then run the shortest possible chat through SingleAssistant and watch the console. A 401 means the selected entry's api_key does not belong to the endpoint in its base_url; check which entry the filter actually picked. A model-not-found error is an id typo in the entry. A connection error usually means base_url lost its /v1 suffix. If the agent loops without tool results, the data keys in config_api_keys are the suspects, not the LLM endpoint. Once requests flow, the APIsRouter console shows per-request model, token counts, and spend. Report-writing runs are long multi-turn conversations, and the usage view shows what one report actually costs before you schedule fifty of them.

curl -s https://api.apisrouter.com/v1/models \
  -H "Authorization: Bearer $APISROUTER_API_KEY" | head -50

FAQ

Does FinRobot support a custom OpenAI-compatible endpoint?

Yes. FinRobot reads AutoGen-style OAI_CONFIG_LIST entries, and entries accept a base_url key alongside model and api_key. Point base_url at the gateway, keep your filter_dict matching the entry's model, and the agents route through it.

Can FinRobot agents run on Claude, DeepSeek, or Qwen models?

Yes. AutoGen forwards the model field as a plain string over /v1/chat/completions, so any id the endpoint serves works. The model name in the entry and in filter_dict just has to match the catalog id exactly.

Why does FinRobot ignore my new OAI_CONFIG_LIST entry?

Almost always the filter_dict. The tutorials filter entries by model name, so an entry whose model does not match the filter is silently excluded. Update filter_dict to your new model id, or load the file without a filter while testing.

Do my Finnhub, FMP, and SEC keys change when I change the LLM endpoint?

No. Market-data credentials live in config_api_keys and load through register_keys_from_json, completely separate from OAI_CONFIG_LIST. Routing the LLM through a gateway does not touch the data pipeline.

Which AutoGen version does this apply to?

FinRobot pins pyautogen 0.2.19 or newer and uses the 0.2-style config_list_from_json loader. The base_url key in config entries is standard across that generation, so no FinRobot code changes are needed.

Does the FinRobot Pro equity module honor base_url too?

Not as documented. Its config.ini exposes an openai_api_key under API_KEYS but no endpoint override as of July 2026. The OAI_CONFIG_LIST routing described here applies to the main FinRobot agents and tutorials.