Skip to main content
An LLM (called a chat model in AgentScope’s class names) drives an agent’s conversation and tool calls, accepting and producing multimodal content beyond plain text. AgentScope currently ships the following chat model classes:

Create Chat Model

Every chat model takes a credential, a model name, and an optional provider-specific Parameters object. The three tabs below show typical setups for streaming, tool calling, and reasoning:
Common constructor arguments shared by every chat model:

Call Chat Model

Invoke the model by calling it with a list of Msg objects, plus optional tools and tool_choice:
The return type follows the model’s stream setting:
  • stream=False: awaits a single ChatResponse carrying the full output.
  • stream=True: awaits an AsyncGenerator[ChatResponse, None]. Intermediate chunks (is_last=False) carry only the delta generated in that step. The final chunk (is_last=True) carries the full accumulated content.
The two tabs below show both modes side by side:
A representative streaming trace, illustrating the delta-then-accumulated pattern:
Each ChatResponse carries content blocks (TextBlock, ThinkingBlock, ToolCallBlock, DataBlock), an is_last flag, a finished_reason (FinishedReason.COMPLETED or FinishedReason.INTERRUPTED), and a ChatUsage recording token counts and elapsed time.

Interrupt Model Call

Interruption at the model layer means asynchronous cancellation: a model call runs inside an asyncio task, and cancelling that task (raising asyncio.CancelledError) stops the in-flight API request, typically because the user interrupted the agent while it was reasoning. Instead of discarding the partial output, ChatModelBase.__call__ catches the cancellation and returns a final ChatResponse carrying the content accumulated so far, marked with finished_reason=FinishedReason.INTERRUPTED. Normal completions end with FinishedReason.COMPLETED, so downstream code can always distinguish a complete answer from a truncated one:
This is the model-layer half of agent interruption: the Agent class builds on the same mechanism to stop a running reasoning-acting loop and keep its context consistent. See Interrupt Agent for the agent-level behavior.

Generate Structured Output

When you need a JSON object that conforms to a Pydantic model or JSON schema, call generate_structured_output instead of __call__. It returns a StructuredResponse whose content is a validated dict matching the schema:
generate_structured_output synthesizes a forced tool call from the schema, then validates and repairs the model’s response.

Formatter

A formatter translates AgentScope’s Msg objects into the list[dict] payload that each provider’s API expects. It is configured via the optional formatter argument on the chat model constructor. Every provider ships two built-in variants: Switch to multi-agent mode by passing the MultiAgent variant; no agent code changes are required:
For non-standard payload shapes (e.g. a provider whose API doesn’t follow the OpenAI or Anthropic conventions), subclass FormatterBase and pass an instance through the same formatter argument.

Multimodal Tool Results

A tool can return images, audio and other DataBlocks, and APIs differ in how much of that they can carry, so the formatter decides how those blocks enter the request: Both paths fall back to text for a media type the target model does not support: base64 data is written to a file and the tool result carries its path, while URL data is given as the URL.

Custom Provider

You can extend AgentScope with your own model provider by implementing a credential and a chat model, then registering the credential.

Step 1: Define the Credential

Subclass CredentialBase with a unique type discriminator and implement get_chat_model_class():

Step 2: Implement the Chat Model

Subclass ChatModelBase, define a Parameters inner class, and implement _call_api. The base class owns retry, streaming accumulation, and interruption handling, so _call_api only needs to translate provider responses into AgentScope ChatResponse chunks:
For streaming custom providers, yield provider deltas as ChatResponse(content=..., is_last=False). If _call_api ends without yielding a final is_last=True chunk, ChatModelBase.__call__ will accumulate the deltas with ChatResponse.append_chat_response() and emit the final response automatically. If the stream is cancelled, it emits the partial accumulated response with finished_reason=FinishedReason.INTERRUPTED.

Step 3: Add Model Cards (optional)

Drop YAML files into a _models/ directory next to your model implementation. Each file describes one model: its capabilities (input_types, output_types), limits (context_size, output_size), and any per-model parameter_overrides (see Integrate with Frontend for the full card format):
MyProviderChatModel.list_models() then loads every YAML in that directory. To pull cards from a different location (for example, a registry your application maintains separately), pass custom_yaml_dir: