v1.3.1: Set Qwen as default provider for QwenClaw
This commit is contained in:
20
README.md
20
README.md
@@ -51,6 +51,26 @@ This will:
|
||||
4. Create default configuration
|
||||
5. Add example scheduled job
|
||||
|
||||
### Configure Qwen Provider (Default)
|
||||
|
||||
QwenClaw uses **Qwen** as the default AI provider.
|
||||
|
||||
1. Get API key: https://platform.qwen.ai/
|
||||
2. Create `rig-service/.env`:
|
||||
```bash
|
||||
cd rig-service
|
||||
cp .env.example .env
|
||||
```
|
||||
3. Edit `.env`:
|
||||
```env
|
||||
QWEN_API_KEY=sk-your-key-here
|
||||
QWEN_BASE_URL=https://api.qwen.ai/v1
|
||||
RIG_DEFAULT_PROVIDER=qwen
|
||||
RIG_DEFAULT_MODEL=qwen-plus
|
||||
```
|
||||
|
||||
See `docs/QWEN-SETUP.md` for detailed setup.
|
||||
|
||||
---
|
||||
|
||||
## Manual Installation
|
||||
|
||||
277
docs/QWEN-SETUP.md
Normal file
277
docs/QWEN-SETUP.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Qwen Provider Setup Guide
|
||||
|
||||
## Overview
|
||||
|
||||
QwenClaw uses **Qwen** as the default AI provider. This guide shows you how to configure and use Qwen with the Rig service.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Get Your Qwen API Key
|
||||
|
||||
1. Visit: https://platform.qwen.ai/
|
||||
2. Sign up or log in
|
||||
3. Go to **API Keys** section
|
||||
4. Click **Create New API Key**
|
||||
5. Copy your key (starts with `sk-...`)
|
||||
|
||||
### 2. Configure Rig Service
|
||||
|
||||
Create `.env` file in `rig-service/`:
|
||||
|
||||
```bash
|
||||
cd rig-service
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Edit `.env`:
|
||||
|
||||
```env
|
||||
# Qwen API Configuration (REQUIRED)
|
||||
QWEN_API_KEY=sk-your-actual-key-here
|
||||
QWEN_BASE_URL=https://api.qwen.ai/v1
|
||||
|
||||
# Defaults (Qwen is default for QwenClaw)
|
||||
RIG_DEFAULT_PROVIDER=qwen
|
||||
RIG_DEFAULT_MODEL=qwen-plus
|
||||
|
||||
# Server settings
|
||||
RIG_HOST=127.0.0.1
|
||||
RIG_PORT=8080
|
||||
```
|
||||
|
||||
### 3. Start Rig Service
|
||||
|
||||
```bash
|
||||
# Build
|
||||
cargo build --release
|
||||
|
||||
# Start
|
||||
cargo run --release
|
||||
```
|
||||
|
||||
### 4. Verify Connection
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8080/health
|
||||
# Should return: {"status":"ok","service":"qwenclaw-rig"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Qwen Models
|
||||
|
||||
| Model | Description | Use Case |
|
||||
|-------|-------------|----------|
|
||||
| `qwen-plus` | **Default** - Balanced performance | General tasks |
|
||||
| `qwen-max` | Most powerful | Complex reasoning |
|
||||
| `qwen-turbo` | Fastest, cheapest | Simple tasks |
|
||||
| `qwen-long` | Long context (256K) | Document analysis |
|
||||
|
||||
---
|
||||
|
||||
## Using Qwen with Rig
|
||||
|
||||
### TypeScript Client
|
||||
|
||||
```typescript
|
||||
import { initRigClient } from "./src/rig";
|
||||
|
||||
const rig = initRigClient();
|
||||
|
||||
// Create agent with Qwen
|
||||
const sessionId = await rig.createAgent({
|
||||
name: "assistant",
|
||||
preamble: "You are a helpful assistant.",
|
||||
provider: "qwen", // Use Qwen
|
||||
model: "qwen-plus", // Qwen model
|
||||
});
|
||||
|
||||
// Execute prompt
|
||||
const result = await rig.executePrompt(sessionId, "Hello!");
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
### HTTP API
|
||||
|
||||
```bash
|
||||
# Create agent with Qwen
|
||||
curl -X POST http://127.0.0.1:8080/api/agents \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "assistant",
|
||||
"preamble": "You are helpful.",
|
||||
"provider": "qwen",
|
||||
"model": "qwen-plus"
|
||||
}'
|
||||
|
||||
# Execute prompt
|
||||
curl -X POST http://127.0.0.1:8080/api/agents/{SESSION_ID}/prompt \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "Hello!"}'
|
||||
```
|
||||
|
||||
### Multi-Agent Council with Qwen
|
||||
|
||||
```typescript
|
||||
const councilId = await rig.createCouncil("Research Team", [
|
||||
{
|
||||
name: "researcher",
|
||||
preamble: "You research thoroughly.",
|
||||
provider: "qwen",
|
||||
model: "qwen-max", // Use most powerful for research
|
||||
},
|
||||
{
|
||||
name: "writer",
|
||||
preamble: "You write clearly.",
|
||||
provider: "qwen",
|
||||
model: "qwen-plus", // Balanced for writing
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await rig.executeCouncil(councilId, "Write a report");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alternative Providers
|
||||
|
||||
### OpenAI (Fallback)
|
||||
|
||||
```env
|
||||
# In rig-service/.env
|
||||
OPENAI_API_KEY=sk-...
|
||||
RIG_DEFAULT_PROVIDER=openai
|
||||
RIG_DEFAULT_MODEL=gpt-4o
|
||||
```
|
||||
|
||||
### Anthropic Claude
|
||||
|
||||
```env
|
||||
# In rig-service/.env
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
RIG_DEFAULT_PROVIDER=anthropic
|
||||
RIG_DEFAULT_MODEL=claude-3-5-sonnet
|
||||
```
|
||||
|
||||
### Ollama (Local)
|
||||
|
||||
```env
|
||||
# In rig-service/.env
|
||||
RIG_DEFAULT_PROVIDER=ollama
|
||||
RIG_DEFAULT_MODEL=qwen2.5:7b
|
||||
# No API key needed - runs locally
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "QWEN_API_KEY not set"
|
||||
|
||||
**Error:**
|
||||
```
|
||||
Error: QWEN_API_KEY not set. Get it from https://platform.qwen.ai
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
1. Get API key from https://platform.qwen.ai
|
||||
2. Add to `rig-service/.env`:
|
||||
```env
|
||||
QWEN_API_KEY=sk-your-key
|
||||
```
|
||||
3. Restart Rig service
|
||||
|
||||
### "Invalid API key"
|
||||
|
||||
**Error:**
|
||||
```
|
||||
Rig prompt execution failed: Invalid API key
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
1. Verify API key is correct (no extra spaces)
|
||||
2. Check key is active in Qwen dashboard
|
||||
3. Ensure sufficient credits/quota
|
||||
|
||||
### Connection Timeout
|
||||
|
||||
**Error:**
|
||||
```
|
||||
Failed to connect to Qwen API
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
1. Check internet connection
|
||||
2. Verify `QWEN_BASE_URL` is correct
|
||||
3. Try alternative: `https://api.qwen.ai/v1`
|
||||
|
||||
---
|
||||
|
||||
## Cost Optimization
|
||||
|
||||
### Use Appropriate Models
|
||||
|
||||
| Task | Recommended Model | Cost |
|
||||
|------|------------------|------|
|
||||
| Simple Q&A | `qwen-turbo` | $ |
|
||||
| General tasks | `qwen-plus` | $$ |
|
||||
| Complex reasoning | `qwen-max` | $$$ |
|
||||
| Long documents | `qwen-long` | $$ |
|
||||
|
||||
### Example: Task-Based Routing
|
||||
|
||||
```typescript
|
||||
// Simple task - use turbo
|
||||
const simpleAgent = await rig.createAgent({
|
||||
name: "quick",
|
||||
model: "qwen-turbo",
|
||||
});
|
||||
|
||||
// Complex task - use max
|
||||
const complexAgent = await rig.createAgent({
|
||||
name: "analyst",
|
||||
model: "qwen-max",
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `QWEN_API_KEY` | ✅ For Qwen | - | Your Qwen API key |
|
||||
| `QWEN_BASE_URL` | ❌ | `https://api.qwen.ai/v1` | API endpoint |
|
||||
| `RIG_DEFAULT_PROVIDER` | ❌ | `qwen` | Default provider |
|
||||
| `RIG_DEFAULT_MODEL` | ❌ | `qwen-plus` | Default model |
|
||||
|
||||
### Provider Values
|
||||
|
||||
| Value | Provider | Models |
|
||||
|-------|----------|--------|
|
||||
| `qwen` | Qwen | qwen-plus, qwen-max, qwen-turbo |
|
||||
| `openai` | OpenAI | gpt-4o, gpt-4, gpt-3.5 |
|
||||
| `anthropic` | Anthropic | claude-3-5-sonnet, claude-3 |
|
||||
| `ollama` | Ollama | Any local model |
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- **Qwen Platform**: https://platform.qwen.ai/
|
||||
- **Qwen Docs**: https://help.qwen.ai/
|
||||
- **Pricing**: https://qwen.ai/pricing
|
||||
- **Rig Integration**: `docs/RIG-INTEGRATION.md`
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
Issues? Check:
|
||||
1. `docs/RIG-STATUS.md` - Known issues
|
||||
2. Rig service logs: `cargo run --release --verbose`
|
||||
3. Qwen status: https://status.qwen.ai/
|
||||
@@ -7,16 +7,20 @@ RIG_PORT=8080
|
||||
# Database path for vector store
|
||||
RIG_DATABASE_PATH=./rig-store.db
|
||||
|
||||
# Model providers (get keys from respective platforms)
|
||||
# OpenAI: https://platform.openai.com/api-keys
|
||||
# Default provider (QwenClaw uses Qwen by default)
|
||||
RIG_DEFAULT_PROVIDER=qwen
|
||||
RIG_DEFAULT_MODEL=qwen-plus
|
||||
|
||||
# Qwen API Configuration
|
||||
# Get your Qwen API key from: https://platform.openai.com/
|
||||
# Or use compatible API endpoints (OpenAI-compatible)
|
||||
QWEN_API_KEY=your-qwen-api-key-here
|
||||
QWEN_BASE_URL=https://api.qwen.ai/v1
|
||||
|
||||
# Alternative: OpenAI (fallback)
|
||||
# Get from: https://platform.openai.com/api-keys
|
||||
OPENAI_API_KEY=your-openai-api-key-here
|
||||
|
||||
# Anthropic: https://console.anthropic.com/settings/keys
|
||||
# Alternative: Anthropic (fallback)
|
||||
# Get from: https://console.anthropic.com/settings/keys
|
||||
ANTHROPIC_API_KEY=your-anthropic-api-key-here
|
||||
|
||||
# Qwen: (if using Qwen API)
|
||||
# QWEN_API_KEY=your-qwen-api-key-here
|
||||
|
||||
# Defaults
|
||||
RIG_DEFAULT_PROVIDER=openai
|
||||
RIG_DEFAULT_MODEL=gpt-4o
|
||||
|
||||
@@ -88,12 +88,19 @@ impl AgentManager {
|
||||
.await
|
||||
.ok_or_else(|| anyhow::anyhow!("Session not found"))?;
|
||||
|
||||
// Get API key based on provider
|
||||
let api_key = self.get_api_key(&session.config.provider)?;
|
||||
// Get provider config (API key + optional base URL)
|
||||
let (api_key, base_url) = self.get_provider_config(&session.config.provider)?;
|
||||
|
||||
// Create Rig agent with OpenAI provider
|
||||
// Note: Rig uses unified provider interface
|
||||
let client = openai::Client::new(&api_key);
|
||||
// Create Rig agent with OpenAI-compatible provider
|
||||
// Qwen uses OpenAI-compatible API, so we can use the OpenAI client
|
||||
let mut client_builder = openai::ClientBuilder::new(&api_key);
|
||||
|
||||
// Use custom base URL if provided (for Qwen or other compatible APIs)
|
||||
if let Some(url) = base_url {
|
||||
client_builder = client_builder.base_url(&url);
|
||||
}
|
||||
|
||||
let client = client_builder.build();
|
||||
|
||||
let agent = client
|
||||
.agent(&session.config.model)
|
||||
@@ -181,26 +188,36 @@ impl AgentManager {
|
||||
Ok(results.join("\n\n---\n\n"))
|
||||
}
|
||||
|
||||
/// Get API key for provider
|
||||
fn get_api_key(&self, provider: &str) -> Result<String> {
|
||||
/// Get API key and base URL for provider
|
||||
fn get_provider_config(&self, provider: &str) -> Result<(String, Option<String>)> {
|
||||
match provider.to_lowercase().as_str() {
|
||||
"openai" => {
|
||||
std::env::var("OPENAI_API_KEY")
|
||||
.map_err(|_| anyhow::anyhow!("OPENAI_API_KEY not set"))
|
||||
"qwen" | "qwen-plus" | "qwen-max" => {
|
||||
let api_key = std::env::var("QWEN_API_KEY")
|
||||
.map_err(|_| anyhow::anyhow!("QWEN_API_KEY not set. Get it from https://platform.qwen.ai"))?;
|
||||
let base_url = std::env::var("QWEN_BASE_URL").ok();
|
||||
Ok((api_key, base_url))
|
||||
}
|
||||
"anthropic" => {
|
||||
std::env::var("ANTHROPIC_API_KEY")
|
||||
.map_err(|_| anyhow::anyhow!("ANTHROPIC_API_KEY not set"))
|
||||
"openai" | "gpt-4" | "gpt-4o" | "gpt-3.5" => {
|
||||
let api_key = std::env::var("OPENAI_API_KEY")
|
||||
.map_err(|_| anyhow::anyhow!("OPENAI_API_KEY not set"))?;
|
||||
Ok((api_key, None))
|
||||
}
|
||||
"qwen" | "default" => {
|
||||
// Fall back to OpenAI for now
|
||||
std::env::var("OPENAI_API_KEY")
|
||||
.or_else(|_| std::env::var("QWEN_API_KEY"))
|
||||
.map_err(|_| anyhow::anyhow!("No API key found (tried OPENAI_API_KEY, QWEN_API_KEY)"))
|
||||
"anthropic" | "claude" | "claude-3" => {
|
||||
let api_key = std::env::var("ANTHROPIC_API_KEY")
|
||||
.map_err(|_| anyhow::anyhow!("ANTHROPIC_API_KEY not set"))?;
|
||||
Ok((api_key, None))
|
||||
}
|
||||
"ollama" | "local" => {
|
||||
// Ollama doesn't need API key, uses localhost
|
||||
Ok(("".to_string(), Some("http://localhost:11434".to_string())))
|
||||
}
|
||||
_ => {
|
||||
std::env::var("OPENAI_API_KEY")
|
||||
.map_err(|_| anyhow::anyhow!("Unknown provider '{}' and no OPENAI_API_KEY set", provider))
|
||||
// Default to Qwen for QwenClaw
|
||||
let api_key = std::env::var("QWEN_API_KEY")
|
||||
.or_else(|_| std::env::var("OPENAI_API_KEY"))
|
||||
.map_err(|_| anyhow::anyhow!("No API key found. Set QWEN_API_KEY or OPENAI_API_KEY"))?;
|
||||
let base_url = std::env::var("QWEN_BASE_URL").ok();
|
||||
Ok((api_key, base_url))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ pub struct Config {
|
||||
pub port: u16,
|
||||
/// Database path for vector store
|
||||
pub database_path: String,
|
||||
/// Default model provider
|
||||
/// Default model provider (Qwen for QwenClaw)
|
||||
pub default_provider: String,
|
||||
/// Default model name
|
||||
pub default_model: String,
|
||||
/// API keys for providers
|
||||
pub qwen_api_key: Option<String>,
|
||||
pub openai_api_key: Option<String>,
|
||||
pub anthropic_api_key: Option<String>,
|
||||
pub qwen_api_key: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -31,13 +31,14 @@ impl Config {
|
||||
.context("Invalid RIG_PORT")?,
|
||||
database_path: std::env::var("RIG_DATABASE_PATH")
|
||||
.unwrap_or_else(|_| "rig-store.db".to_string()),
|
||||
// QwenClaw default: Qwen provider
|
||||
default_provider: std::env::var("RIG_DEFAULT_PROVIDER")
|
||||
.unwrap_or_else(|_| "openai".to_string()),
|
||||
.unwrap_or_else(|_| "qwen".to_string()),
|
||||
default_model: std::env::var("RIG_DEFAULT_MODEL")
|
||||
.unwrap_or_else(|_| "gpt-4".to_string()),
|
||||
.unwrap_or_else(|_| "qwen-plus".to_string()),
|
||||
qwen_api_key: std::env::var("QWEN_API_KEY").ok(),
|
||||
openai_api_key: std::env::var("OPENAI_API_KEY").ok(),
|
||||
anthropic_api_key: std::env::var("ANTHROPIC_API_KEY").ok(),
|
||||
qwen_api_key: std::env::var("QWEN_API_KEY").ok(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user