Spaces:
Sleeping
Sleeping
# AWorld LLM Interface | |
A unified interface for interacting with various LLM providers through a consistent API. | |
## Features | |
- Unified API for multiple LLM providers. Currently, only OpenAI and Anthropic are supported. | |
- Synchronous and asynchronous calls with optional initialization control | |
- Streaming responses support | |
- Tool calls support | |
- Unified ModelResponse object for all provider responses | |
- Easy extension with custom providers | |
## Supported Providers | |
- `openai`: Models supporting OpenAI API protocol (OpenAI, compatible models) | |
- `anthropic`: Models supporting Anthropic API protocol (Claude models) | |
- `azure_openai`: Azure OpenAI service | |
## Basic Usage | |
### Quick Start | |
```python | |
from aworld.config.conf import AgentConfig | |
from aworld.models.llm import get_llm_model, call_llm_model, acall_llm_model | |
# Create configuration | |
config = AgentConfig( | |
llm_provider="openai", # Options: "openai", "anthropic", "azure_openai" | |
llm_model_name="gpt-4o", | |
llm_temperature=0.0, | |
llm_api_key="your_api_key", | |
llm_base_url="your_llm_server_address" | |
) | |
# Initialize the model | |
model = get_llm_model(config) | |
# Prepare messages | |
messages = [ | |
{"role": "system", "content": "You are a helpful AI assistant."}, | |
{"role": "user", "content": "Explain Python in three sentences."} | |
] | |
# Get response | |
response = model.completion(messages) | |
print(response.content) # Access content directly from ModelResponse | |
``` | |
### Using call_llm_model (Recommended) | |
```python | |
from aworld.models.llm import get_llm_model, call_llm_model | |
# Initialize model | |
model = get_llm_model( | |
llm_provider="openai", | |
model_name="gpt-4o", | |
api_key="your_api_key", | |
base_url="https://api.openai.com/v1" | |
) | |
# Prepare messages | |
messages = [ | |
{"role": "system", "content": "You are a helpful AI assistant."}, | |
{"role": "user", "content": "Write a short poem about programming."} | |
] | |
# Using call_llm_model - returns ModelResponse object | |
response = call_llm_model(model, messages) | |
print(response.content) # Access content directly from ModelResponse | |
# Stream response with call_llm_model | |
for chunk in call_llm_model(model, messages, temperature=0.7, stream=True): | |
if chunk.content: | |
print(chunk.content, end="", flush=True) | |
``` | |
### Asynchronous Calls with acall_llm_model | |
```python | |
import asyncio | |
from aworld.models.llm import get_llm_model, acall_llm_model | |
async def main(): | |
# Initialize model | |
model = get_llm_model( | |
llm_provider="anthropic", | |
model_name="claude-3-5-sonnet-20241022", | |
api_key="your_anthropic_api_key" | |
) | |
# Prepare messages | |
messages = [ | |
{"role": "user", "content": "List 3 effective ways to learn programming."} | |
] | |
# Async call with acall_llm_model | |
response = await acall_llm_model(model, messages) | |
print(response.content) | |
# Async streaming with acall_llm_model | |
print("\nStreaming response:") | |
async for chunk in await acall_llm_model(model, messages, stream=True): | |
if chunk.content: | |
print(chunk.content, end="", flush=True) | |
# Run async function | |
asyncio.run(main()) | |
``` | |
### Selective Sync/Async Initialization | |
For performance optimization, you can control whether to initialize synchronous or asynchronous providers: | |
By default, both `sync_enabled` and `async_enabled` are set to `True`, which means both synchronous and asynchronous providers will be initialized. | |
```python | |
# Initialize only synchronous provider | |
model = get_llm_model( | |
llm_provider="openai", | |
model_name="gpt-4o", | |
sync_enabled=True, # Initialize sync provider | |
async_enabled=False, # Don't initialize async provider | |
api_key="your_api_key" | |
) | |
# Initialize only asynchronous provider | |
model = get_llm_model( | |
llm_provider="anthropic", | |
model_name="claude-3-5-sonnet-20241022", | |
sync_enabled=False, # Don't initialize sync provider | |
async_enabled=True, # Initialize async provider | |
api_key="your_api_key" | |
) | |
# Initialize both (default behavior) | |
model = get_llm_model( | |
llm_provider="openai", | |
model_name="gpt-4o", | |
sync_enabled=True, | |
async_enabled=True | |
) | |
``` | |
### HTTP Client Mode | |
You can use direct HTTP requests instead of the SDK by specifying `client_type=ClientType.HTTP` parameter: | |
```python | |
from aworld.config.conf import AgentConfig, ClientType | |
from aworld.models.llm import get_llm_model, call_llm_model | |
# Initialize model with HTTP client mode | |
model = get_llm_model( | |
llm_provider="openai", | |
model_name="gpt-4o", | |
api_key="your_api_key", | |
base_url="https://api.openai.com/v1", | |
client_type=ClientType.HTTP # Use HTTP client instead of SDK | |
) | |
# Use it exactly the same way as SDK mode | |
messages = [ | |
{"role": "system", "content": "You are a helpful AI assistant."}, | |
{"role": "user", "content": "Tell me a short joke."} | |
] | |
# The model uses HTTP requests under the hood | |
response = call_llm_model(model, messages) | |
print(response.content) | |
# Streaming also works with HTTP client | |
for chunk in call_llm_model(model, messages, stream=True): | |
if chunk.content: | |
print(chunk.content, end="", flush=True) | |
``` | |
This approach can be useful when: | |
- You need more control over the HTTP requests | |
- You have compatibility issues with the official SDK | |
- You're using a model that follows OpenAI API protocol but isn't fully compatible with the SDK | |
### Tool Calls Support | |
```python | |
from aworld.models.llm import get_llm_model, call_llm_model | |
import json | |
# Initialize model | |
model = get_llm_model( | |
llm_provider="openai", | |
model_name="gpt-4o", | |
api_key="your_api_key" | |
) | |
# Define tools | |
tools = [ | |
{ | |
"type": "function", | |
"function": { | |
"name": "get_weather", | |
"description": "Get the current weather in a given location", | |
"parameters": { | |
"type": "object", | |
"properties": { | |
"location": { | |
"type": "string", | |
"description": "The city and state, e.g. San Francisco, CA" | |
} | |
}, | |
"required": ["location"] | |
} | |
} | |
} | |
] | |
# Prepare messages | |
messages = [ | |
{"role": "user", "content": "What's the weather like in San Francisco?"} | |
] | |
# Call model with tools | |
response = call_llm_model(model, messages, tools=tools, tool_choice="auto") | |
# Check for tool calls | |
if response.tool_calls: | |
for tool_call in response.tool_calls: | |
print(f"Tool name: {tool_call.name}") | |
print(f"Arguments: {tool_call.arguments}") | |
# Handle tool call | |
if tool_call.name == "get_weather": | |
# Parse arguments | |
args = json.loads(tool_call.arguments) | |
location = args.get("location") | |
# Mock getting weather data | |
weather = "Sunny, 25°C" | |
# Add tool response to messages | |
messages.append(response.message) # Add assistant message | |
messages.append({ | |
"role": "tool", | |
"tool_call_id": tool_call.id, | |
"name": tool_call.name, | |
"content": f"{{\"weather\": \"{weather}\"}}" | |
}) | |
# Call model again | |
final_response = call_llm_model(model, messages) | |
print("\nFinal response:", final_response.content) | |
else: | |
print("\nResponse content:", response.content) | |
``` | |
### Asynchronous Calls | |
```python | |
import asyncio | |
from aworld.models.llm import get_llm_model | |
async def main(): | |
# Initialize model | |
model = get_llm_model( | |
llm_provider="anthropic", | |
model_name="claude-3-5-sonnet-20241022", | |
temperature=0.0 | |
) | |
# Prepare messages | |
messages = [ | |
{"role": "user", "content": "Explain machine learning briefly."} | |
] | |
# Async call | |
response = await model.acompletion(messages) | |
print(response.content) | |
# Run async function | |
asyncio.run(main()) | |
``` | |
### Streaming Responses | |
```python | |
# Synchronous streaming | |
for chunk in model.stream_completion(messages): | |
print(chunk.content, end="", flush=True) | |
# Asynchronous streaming | |
async for chunk in model.astream_completion(messages): | |
print(chunk.content, end="", flush=True) | |
``` | |
## ModelResponse Object | |
All responses are encapsulated in a unified `ModelResponse` object with these key attributes: | |
- `id`: Response ID | |
- `model`: Model name used | |
- `content`: Generated text content | |
- `tool_calls`: List of tool calls (if any) | |
- `usage`: Token usage statistics | |
- `error`: Error message (if any) | |
- `message`: Complete message object for subsequent API calls | |
Example: | |
```python | |
response = call_llm_model(model, messages) | |
print(f"Content: {response.content}") | |
print(f"Model: {response.model}") | |
print(f"Total tokens: {response.usage['total_tokens']}") | |
# Get complete message for next call | |
messages.append(response.message) | |
``` | |
## API Parameters | |
Essential parameters for model calls: | |
- `messages`: List of message dictionaries with `role` and `content` keys | |
- `temperature`: Controls response randomness (0.0-1.0) | |
- `max_tokens`: Maximum tokens to generate | |
- `stop`: List of stopping sequences | |
- `tools`: List of tool definitions | |
- `tool_choice`: Tool choice strategy | |
## Automatic Provider Detection | |
The system can automatically identify the provider based on model name or API endpoint: | |
```python | |
# Detect Anthropic based on model name | |
model = get_llm_model(model_name="claude-3-5-sonnet-20241022") | |
``` | |
## Creating Custom Providers | |
Implement your own provider by extending `LLMProviderBase`: | |
```python | |
from aworld.models.llm import LLMProviderBase, register_llm_provider | |
from aworld.models.model_response import ModelResponse, ToolCall | |
class CustomProvider(LLMProviderBase): | |
def _init_provider(self): | |
# Initialize your API client | |
return { | |
"api_key": self.api_key, | |
"endpoint": self.base_url | |
} | |
def _init_async_provider(self): | |
# Initialize your asynchronous API client (optional) | |
# If not implemented, async methods will raise NotImplementedError | |
return None | |
def preprocess_messages(self, messages): | |
# Convert standard format to your API format | |
return messages | |
def postprocess_response(self, response): | |
# Convert API response to ModelResponse | |
return ModelResponse( | |
id="response_id", | |
model=self.model_name, | |
content=response.get("text", ""), | |
tool_calls=None # Parse ToolCall objects if supported | |
) | |
def completion(self, messages, temperature=0.0, **kwargs): | |
# Implement the actual API call | |
processed = self.preprocess_messages(messages) | |
# Call your API here... | |
response = {"text": "Response from custom provider"} | |
return self.postprocess_response(response) | |
async def acompletion(self, messages, temperature=0.0, **kwargs): | |
# Implement async API call | |
# Similar to completion but asynchronous | |
response = {"text": "Async response from custom provider"} | |
return self.postprocess_response(response) | |
# Register your provider | |
register_llm_provider("custom_provider", CustomProvider) | |
# Use it like any other provider | |
model = get_llm_model(llm_provider="custom_provider", model_name="custom-model") | |
``` | |
## API Key Management | |
Keys are retrieved in this order: | |
1. Direct `api_key` parameter | |
2. Environment variable in `.env` file | |
3. System environment variable | |
Example for OpenAI: `OPENAI_API_KEY` in parameters → `.env` → system env | |