File size: 11,581 Bytes
ae64487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# 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