This guide shows how to replace simulation functions with actual AI API calls from OpenAI, Anthropic, and Hugging Face.
OpenAI (GPT-3.5/GPT-4):
# Sign up at https://platform.openai.com/
# Go to API Keys section
# Create new secret key
export OPENAI_API_KEY="sk-your-openai-key-here"Anthropic (Claude):
# Sign up at https://console.anthropic.com/
# Go to API Keys section
# Create new API key
export ANTHROPIC_API_KEY="sk-ant-your-anthropic-key-here"Hugging Face:
# Sign up at https://huggingface.co/
# Go to Settings > Access Tokens
# Create new token with read permissions
export HF_API_KEY="hf_your-huggingface-token-here"Create a .env file in your project root:
cp .env.example .env
# Edit .env with your actual API keysOr set environment variables directly:
export OPENAI_API_KEY="your-openai-key"
export ANTHROPIC_API_KEY="your-anthropic-key"
export HF_API_KEY="your-huggingface-key"
export FRAUD_API_ENDPOINT="http://your-ml-service.com/api/fraud"
export TIER_API_ENDPOINT="http://your-ml-service.com/api/tier"// examples/real_ai_integration.rs
cargo run --example real_ai_integrationFeatures:
- ✅ OpenAI GPT-3.5 sentiment analysis
- ✅ Anthropic Claude business decisions
- ✅ Hugging Face sentiment models
- ✅ Custom ML API integration
- ✅ Error handling with fallbacks
// examples/production_ai_service.rs
cargo run --example production_ai_serviceFeatures:
- ✅ Intelligent caching with TTL
- ✅ Automatic retry with exponential backoff
- ✅ Cost tracking and monitoring
- ✅ Multi-AI model comparison
- ✅ Graceful fallback strategies
// examples/ai_rest_api_production.rs
cargo run --example ai_rest_api_productionFeatures:
- ✅ Production REST API with AI integration
- ✅ Real-time cost tracking
- ✅ Cache performance monitoring
- ✅ Provider usage statistics
- ✅ Health checks and monitoring
async fn call_openai_sentiment_api(text: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let client = reqwest::Client::new();
let request_body = json!({
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "Analyze sentiment. Respond with: positive, negative, or neutral"
},
{
"role": "user",
"content": format!("Sentiment: {}", text)
}
],
"max_tokens": 10,
"temperature": 0.1
});
let response = client
.post("https://api.openai.com/v1/chat/completions")
.header("Authorization", format!("Bearer {}", env::var("OPENAI_API_KEY")?))
.header("Content-Type", "application/json")
.json(&request_body)
.send()
.await?;
let response_json: serde_json::Value = response.json().await?;
let sentiment = response_json["choices"][0]["message"]["content"]
.as_str()
.unwrap_or("neutral")
.trim()
.to_lowercase();
Ok(sentiment)
}async fn call_anthropic_decision(question: &str, context: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let client = reqwest::Client::new();
let request_body = json!({
"model": "claude-3-sonnet-20240229",
"max_tokens": 100,
"messages": [
{
"role": "user",
"content": format!("Business Decision: {}\nContext: {}\nRespond: approve, deny, or review", question, context)
}
]
});
let response = client
.post("https://api.anthropic.com/v1/messages")
.header("x-api-key", env::var("ANTHROPIC_API_KEY")?)
.header("Content-Type", "application/json")
.header("anthropic-version", "2023-06-01")
.json(&request_body)
.send()
.await?;
let response_json: serde_json::Value = response.json().await?;
let decision_text = response_json["content"][0]["text"]
.as_str()
.unwrap_or("review")
.to_lowercase();
let decision = if decision_text.contains("approve") {
"approve"
} else if decision_text.contains("deny") {
"deny"
} else {
"review"
};
Ok(decision.to_string())
}async fn call_huggingface_sentiment(text: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let client = reqwest::Client::new();
let request_body = json!({
"inputs": text
});
let response = client
.post("https://api-inference.huggingface.co/models/cardiffnlp/twitter-roberta-base-sentiment-latest")
.header("Authorization", format!("Bearer {}", env::var("HF_API_KEY")?))
.header("Content-Type", "application/json")
.json(&request_body)
.send()
.await?;
let response_json: serde_json::Value = response.json().await?;
// Parse Hugging Face response format
if let Some(predictions) = response_json.as_array() {
if let Some(first_prediction) = predictions.first() {
if let Some(predictions_array) = first_prediction.as_array() {
let mut best_sentiment = "neutral";
let mut best_score = 0.0;
for prediction in predictions_array {
if let (Some(label), Some(score)) = (
prediction["label"].as_str(),
prediction["score"].as_f64()
) {
if score > best_score {
best_score = score;
best_sentiment = match label {
"LABEL_0" => "negative",
"LABEL_1" => "neutral",
"LABEL_2" => "positive",
_ => "neutral"
};
}
}
}
return Ok(best_sentiment.to_string());
}
}
}
Ok("neutral".to_string())
}pub struct AIServiceConfig {
pub max_retries: u32,
pub base_delay_ms: u64,
pub max_delay_ms: u64,
pub timeout_seconds: u64,
}
async fn call_with_retry<F, Fut, T>(
config: &AIServiceConfig,
operation: F,
) -> Result<T, Box<dyn std::error::Error + Send + Sync>>
where
F: Fn() -> Fut,
Fut: std::future::Future<Output = Result<T, Box<dyn std::error::Error + Send + Sync>>>,
{
let mut delay = config.base_delay_ms;
for attempt in 1..=config.max_retries {
match operation().await {
Ok(result) => return Ok(result),
Err(e) => {
if attempt == config.max_retries {
return Err(e);
}
eprintln!("Attempt {}/{} failed: {}", attempt, config.max_retries, e);
tokio::time::sleep(Duration::from_millis(delay)).await;
delay = std::cmp::min(delay * 2, config.max_delay_ms);
}
}
}
unreachable!()
}use std::collections::HashMap;
use std::time::{Duration, Instant};
pub struct AICache {
cache: HashMap<String, (String, Instant, f64)>, // response, timestamp, cost
ttl: Duration,
}
impl AICache {
pub fn get(&self, key: &str) -> Option<String> {
if let Some((response, timestamp, _)) = self.cache.get(key) {
if timestamp.elapsed() < self.ttl {
return Some(response.clone());
}
}
None
}
pub fn put(&mut self, key: String, response: String, cost: f64) {
self.cache.insert(key, (response, Instant::now(), cost));
self.cleanup_expired();
}
fn cleanup_expired(&mut self) {
self.cache.retain(|_, (_, timestamp, _)| timestamp.elapsed() < self.ttl);
}
}pub struct CostTracker {
total_cost: f64,
monthly_limit: f64,
provider_costs: HashMap<String, f64>,
}
impl CostTracker {
pub fn can_afford(&self, estimated_cost: f64) -> bool {
self.total_cost + estimated_cost <= self.monthly_limit
}
pub fn record_usage(&mut self, provider: &str, cost: f64) {
self.total_cost += cost;
*self.provider_costs.entry(provider.to_string()).or_insert(0.0) += cost;
}
pub fn get_cost_breakdown(&self) -> HashMap<String, f64> {
self.provider_costs.clone()
}
}# Start the AI REST API
cargo run --example ai_rest_api_production
# Run comprehensive tests
./test_real_ai.sh# Check AI service statistics
curl http://localhost:3000/api/v1/ai/stats | jq '.'
# Monitor costs
curl http://localhost:3000/api/v1/ai/stats | jq '.total_cost_estimate'
# Check cache performance
curl http://localhost:3000/api/v1/ai/stats | jq '.cache_performance'# Install hey for load testing
go install github.com/rakyll/hey@latest
# Test API performance
hey -n 100 -c 10 -m POST \
-H "Content-Type: application/json" \
-d '{"facts":{"CustomerMessage":{"text":"Test message","provider":"openai"}}}' \
http://localhost:3000/api/v1/rules/execute| Provider | Model | Cost per 1K tokens | Use Case |
|---|---|---|---|
| OpenAI | GPT-3.5-turbo | $0.0015/$0.002 | Fast sentiment analysis |
| OpenAI | GPT-4 | $0.03/$0.06 | Complex reasoning |
| Anthropic | Claude-3-Sonnet | $0.003/$0.015 | Business decisions |
| Hugging Face | Inference API | $0.001 | Basic sentiment analysis |
- Caching: Cache identical requests (50-80% cost reduction)
- Model Selection: Use cheaper models for simple tasks
- Batch Processing: Group multiple requests when possible
- Fallback Logic: Use rule-based logic when AI fails
- Rate Limiting: Prevent cost runaway in high-traffic scenarios
// Production-optimized configuration
let config = AIServiceConfig {
enable_caching: true,
cache_ttl_seconds: 3600, // 1 hour
max_retries: 3,
request_timeout_seconds: 15,
monthly_cost_limit: 100.0, // $100/month
fallback_enabled: true,
rate_limit_per_minute: 60,
};# Use environment variables (never commit keys)
export OPENAI_API_KEY="$(cat /path/to/secure/openai.key)"
# Use secret management in production
kubectl create secret generic ai-keys \
--from-literal=openai-key="$OPENAI_API_KEY" \
--from-literal=anthropic-key="$ANTHROPIC_API_KEY"- Data Retention: Don't log sensitive customer data
- Encryption: Encrypt data in transit and at rest
- Compliance: Follow GDPR, CCPA, SOC2 requirements
- Audit Logs: Track all AI API calls for compliance
use std::collections::HashMap;
use std::time::{Duration, Instant};
pub struct RateLimiter {
requests: HashMap<String, Vec<Instant>>,
limit_per_minute: u32,
}
impl RateLimiter {
pub fn can_proceed(&mut self, key: &str) -> bool {
let now = Instant::now();
let requests = self.requests.entry(key.to_string()).or_insert_with(Vec::new);
// Remove requests older than 1 minute
requests.retain(|×tamp| now.duration_since(timestamp) < Duration::from_secs(60));
if requests.len() >= self.limit_per_minute as usize {
return false;
}
requests.push(now);
true
}
}# kubernetes deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-rule-engine
spec:
replicas: 3
selector:
matchLabels:
app: ai-rule-engine
template:
metadata:
labels:
app: ai-rule-engine
spec:
containers:
- name: ai-rule-engine
image: your-registry/ai-rule-engine:latest
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: ai-keys
key: openai-key
ports:
- containerPort: 3000use redis::AsyncCommands;
pub struct RedisCache {
client: redis::Client,
}
impl RedisCache {
pub async fn get(&self, key: &str) -> Option<String> {
let mut conn = self.client.get_async_connection().await.ok()?;
conn.get(key).await.ok()
}
pub async fn set(&self, key: &str, value: &str, ttl: Duration) {
if let Ok(mut conn) = self.client.get_async_connection().await {
let _: Result<(), _> = conn.set_ex(key, value, ttl.as_secs()).await;
}
}
}use tracing::{info, warn, error, instrument};
#[instrument]
pub async fn analyze_sentiment_with_monitoring(
text: &str,
provider: &str,
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let start = Instant::now();
match provider {
"openai" => {
let result = call_openai_sentiment_api(text).await;
info!(
provider = provider,
duration_ms = start.elapsed().as_millis(),
success = result.is_ok(),
"AI sentiment analysis completed"
);
result
}
_ => Err("Unsupported provider".into())
}
}- Start with one provider (OpenAI is easiest to begin with)
- Implement caching for cost efficiency
- Add error handling with graceful fallbacks
- Monitor costs and set appropriate limits
- Scale gradually based on usage patterns
- Add security measures for production deployment