Point AutoGen at a custom OpenAI-compatible endpoint.

Updated 2026-07-16

AutoGen 0.4+ configures models through OpenAIChatCompletionClient. Set base_url to https://api.apisrouter.com/v1, declare model_info for non-OpenAI ids, and every agent and team in the runtime routes through one endpoint with the whole catalog addressable by id.

Quick answer: base_url plus model_info.

In current AutoGen (the 0.4+ rewrite), models are configured on OpenAIChatCompletionClient from the autogen-ext package. Two arguments carry the custom-endpoint case: base_url, documented as required when the model is not hosted on OpenAI, and model_info, documented as required when the model name is not a valid OpenAI model. Point base_url at https://api.apisrouter.com/v1, pass your key, and declare what the model can do. model_info is the part the brief version of this setup always omits. For an id like claude-sonnet-4-6, AutoGen has no built-in capability record, so you state one: whether the model handles vision, function calling, JSON output, structured output, and which family it belongs to. Omit it with a non-OpenAI id and client construction fails before any request is made.

import os
from autogen_ext.models.openai import OpenAIChatCompletionClient

client = OpenAIChatCompletionClient(
    model="claude-sonnet-4-6",           # any catalog id
    base_url="https://api.apisrouter.com/v1",
    api_key=os.environ["APISROUTER_API_KEY"],
    model_info={
        "vision": False,
        "function_calling": True,
        "json_output": True,
        "structured_output": True,
        "family": "unknown",
    },
)

One client, every agent in the runtime.

AutoGen (microsoft on GitHub, roughly 60K stars) builds multi-agent systems as conversations: AssistantAgents that reason and call tools, teams like RoundRobinGroupChat and SelectorGroupChat that pass work between agents, and termination conditions that decide when the conversation is done. Every agent turn, every selector decision, and every tool-call round trip is a chat-completions request through whichever model client the agent holds. That architecture makes the model client the single point of routing. An OpenAIChatCompletionClient constructed once can be shared across agents, or each agent can hold its own client with a different model id, a planner on claude-opus-4-7, workers on gpt-5.4-mini, a formatter on glm-5.2, all through the same base_url and key. The model field passes through as a plain string, so vendor mixing inside one team is constructor arguments, not new dependencies. Group-chat selectors deserve a note: SelectorGroupChat uses a model to choose the next speaker, and that selector model fires on every turn. It is a high-frequency, low-difficulty slot, exactly the shape a fast id should hold.

Full setup: a two-agent team, and the legacy config_list.

The team below shows the shape: per-agent clients against one endpoint, a strong model where reasoning concentrates and a fast one where it does not. The same client object also powers tool-using AssistantAgents; tool schemas ride the standard request, so function calling works with any id whose model_info declares it. The legacy generation (AutoGen 0.2 and the AG2 fork that continues it) configures models through config_list dictionaries instead: model, base_url, api_key, and api_type set to "openai" per entry. If your codebase passes llm_config to ConversableAgent, you are on this API; the same endpoint and ids work, expressed as dict keys rather than constructor arguments.

import os, asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import MaxMessageTermination
from autogen_ext.models.openai import OpenAIChatCompletionClient

def gateway_client(model_id: str) -> OpenAIChatCompletionClient:
    return OpenAIChatCompletionClient(
        model=model_id,
        base_url="https://api.apisrouter.com/v1",
        api_key=os.environ["APISROUTER_API_KEY"],
        model_info={"vision": False, "function_calling": True,
                    "json_output": True, "structured_output": True,
                    "family": "unknown"},
    )

planner = AssistantAgent("planner", model_client=gateway_client("claude-opus-4-7"))
worker = AssistantAgent("worker", model_client=gateway_client("gpt-5.4-mini"))

team = RoundRobinGroupChat([planner, worker],
                           termination_condition=MaxMessageTermination(8))
print(asyncio.run(team.run(task="Draft a rollout plan for feature flags.")))

Choosing models per agent.

Multi-agent conversations resend the growing transcript on every turn, which makes model placement compound: the same id in a chatty seat costs multiples of what it costs in a quiet one. The per-key usage view shows tokens per model, which maps directly onto seats and is the evidence to rebalance on.

  • Planner and critic agents carry the team's judgment; claude-opus-4-7 and gpt-5.5 belong in these seats because a bad plan or a soft critique propagates through every subsequent turn.
  • Worker agents executing well-scoped subtasks are volume seats where gpt-5.4-mini and glm-5.2 keep the per-turn cost flat; team transcripts grow with every turn, so volume seats dominate token spend.
  • Tool-using agents need dependable function calling; claude-sonnet-4-6 is the reliable middle, and its model_info should declare function_calling truthfully.
  • The SelectorGroupChat speaker-selection model fires every turn on an easy task; give that slot the fastest capable id you have rather than letting it default to the team's strongest.

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 Sonnet 4.6$3.00 / $15.00 per M$2.40 / $12.00 per M
Claude Opus 4.7$5.00 / $25.00 per M$4.00 / $20.00 per M
GPT-5.5$5.00 / $30.00 per M$4.00 / $24.00 per M
GPT-5.4 Mini$0.75 / $4.50 per M$0.60 / $3.60 per M
GLM-5.2$1.14 / $4.00 per M$1.03 / $3.60 per M

Failure modes and version pinning.

Omitted model_info. With a non-OpenAI id, the client raises at construction because it cannot look up capabilities for a name it does not recognize. The fix is to declare the dict, truthfully: function_calling: true on a model that lacks it produces malformed tool loops later, which is a worse failure than the loud one you started with. Two AutoGens, one name. The 0.4+ rewrite (packages autogen-agentchat and autogen-ext) and the legacy 0.2 lineage continued by the AG2 fork share a name and not an API. Tutorials mix freely between them, and imports are the tell: autogen_agentchat and autogen_ext mean current AutoGen with client constructors; a bare autogen import with config_list and llm_config means the legacy lineage. Pin the pair autogen-agentchat plus autogen-ext[openai] for the current API, and do not install the legacy package into the same environment. base_url without /v1. The client appends route paths to the base you give it; the bare host produces connection or 404-shaped failures. https://api.apisrouter.com/v1 is the correct value in both the 0.4 constructor and the legacy config_list entry. Async surprises in scripts. The 0.4 API is async-first; team runs return coroutines. A script that calls team.run() without an event loop gets a coroutine object, not a result. asyncio.run() is the minimal wrapper, as in the example above. Unbounded teams burn unbounded tokens. Termination conditions are part of cost control, not just correctness: a team without a termination condition, or with a generous one plus a chatty model, keeps resending a growing transcript. Set MaxMessageTermination or an equivalent guard before scaling anything.

Who routes AutoGen through a gateway.

  • Teams building mixed-model agent systems, frontier planners with fast workers, without one SDK and credential set per vendor.
  • Researchers comparing team compositions, where each candidate seating is a constructor string and per-key usage prices every experiment automatically.
  • Engineers migrating legacy config_list codebases, since the same endpoint serves both generations during the transition.
  • Operators of long-running or scheduled agent teams, where transcripts compound and a single billing surface keeps per-model spend legible.
  • Developers without access to a given vendor's billing. Top-up based access with no card requirement removes the sign-up dependency per provider.

Verify the endpoint and debug the first team run.

List the gateway's models first; the model argument must match a served id exactly, version suffix included. First-run failures follow a pattern. An error at client construction naming model capabilities means model_info is missing for a non-OpenAI id. A 401 means the key is wrong for the endpoint the client resolved; print the effective base_url before rotating keys. A model-not-found error from the gateway is an id typo. A coroutine object where you expected a result is the async-first API meeting a sync script. And tool loops that produce malformed calls usually trace back to a model_info that overstates what the id supports. Once teams run, the APIsRouter console shows per-request model, token counts, and spend. Multi-agent transcripts make token growth superlinear in conversation length, and the per-model split in the usage view is the fastest way to see which seat is carrying the bill and whether your termination conditions are doing their job.

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

FAQ

Can AutoGen agents use Claude or GLM models through OpenAIChatCompletionClient?

Yes. The client speaks chat completions to whatever base_url names and forwards the model field as a plain string. Any id the gateway serves works, provided you pass model_info declaring the model's capabilities, since AutoGen cannot look up non-OpenAI names.

Why does client construction fail before any request is sent?

model_info is required when the model name is not a valid OpenAI model. Without it the client has no capability record and raises immediately. Declare vision, function_calling, json_output, structured_output, and family for the id you are using.

Which AutoGen am I on, 0.4+ or legacy?

Check the imports. autogen_agentchat and autogen_ext with client constructors is the current 0.4+ API. A bare autogen import configured through config_list and llm_config is the legacy 0.2 lineage, continued by the AG2 fork. Both reach a custom endpoint; the syntax differs.

Can different agents in one team use different models?

Yes. Each AssistantAgent holds its own model_client, so a planner on claude-opus-4-7 and workers on gpt-5.4-mini coexist in one team. Through a single gateway endpoint they share one key and one billing surface.

Does function calling work through the gateway?

Yes. Tool schemas and tool-call responses ride the standard chat-completions protocol. Use ids that genuinely support tool use and declare function_calling: true in model_info; overstating capabilities produces malformed tool loops rather than clean errors.

What should I pin for reproducible teams?

Pin autogen-agentchat and autogen-ext[openai] together, and keep the legacy package out of the same environment. Record each seat's model id alongside results; dated catalog ids keep multi-agent experiments reproducible the way seeds do.