Von Excel zum KI-Agent in 30 Minuten
Ihre Excel-Tabelle hat sich über Jahre entwickelt. Sie verarbeitet Sonderfälle, implementiert komplexe Geschäftsregeln und verkörpert tiefes Domänenwissen. Jetzt möchten Sie, dass ein KI-Agent sie nutzt.
Die meisten Tutorials sagen Ihnen, Sie sollen "einfach als CSV exportieren" oder "in Python neu implementieren." Wir werden etwas Besseres machen: Wir geben Ihrem KI-Agent direkten Zugriff auf Excels Berechnungsengine.
Was wir entwickeln
Einen Kundenservice-KI-Agent, der:
- Genaue Angebote mit Ihrer Preis-Excel berechnet
- Liefertermine mit Ihrem Logistikmodell prüft
- Rabatte basierend auf komplexen Geschäftsregeln anwendet
- Sonderfälle genau wie Ihr Team behandelt
Alles unter Verwendung Ihrer bestehenden Excel-Dateien. Keine Neuimplementierung erforderlich.
Voraussetzungen
# Sie benötigen:
npm install langchain @langchain/openai
# oder
pip install langchain openai
# Und ein SpreadAPI-Konto (kostenlose Stufe funktioniert)
# Registrieren Sie sich unter https://spreadapi.ioSchritt 1: Excel für KI vorbereiten
Ihre Excel-Struktur
PricingModel.xlsx
├── Eingaben
│ ├── B2: Produktcode
│ ├── B3: Menge
│ ├── B4: Kundentyp
│ └── B5: Region
├── Berechnungen (Vor KI verborgen)
│ ├── Komplexe VLOOKUP-Formeln
│ ├── Rabattmatrizen
│ └── Geschäftsregeln
└── Ausgaben
├── E10: Grundpreis
├── E11: Rabattbetrag
├── E12: Endpreis
└── E13: LieferterminUpload zu SpreadAPI
- Bei SpreadAPI Dashboard anmelden
- Neuen Service namens "pricing-model" erstellen
- Ihre Excel hochladen
- Schnittstelle definieren:
{
"inputs": {
"productCode": "B2",
"quantity": "B3",
"customerType": "B4",
"region": "B5"
},
"outputs": {
"basePrice": "E10",
"discount": "E11",
"finalPrice": "E12",
"deliveryDate": "E13"
}
}Schritt 2: Den KI-Agent erstellen
Basis-Agent mit Function Calling
import { ChatOpenAI } from '@langchain/openai';
import { SpreadAPITool } from './spreadapi-tool';
// Das Excel-Berechnungs-Tool definieren
const pricingTool = {
name: "calculate_pricing",
description: "Genaue Preisberechnung mit dem Unternehmens-Preismodell. Verwenden Sie dieses Tool, wann immer Sie Preise anbieten oder Rabatte prüfen müssen.",
parameters: {
type: "object",
properties: {
productCode: {
type: "string",
description: "Produktcode (z.B. 'PRO-001')"
},
quantity: {
type: "number",
description: "Anzahl der Einheiten"
},
customerType: {
type: "string",
enum: ["standard", "premium", "enterprise"],
description: "Art des Kundenkontos"
},
region: {
type: "string",
enum: ["US", "EU", "APAC"],
description: "Region des Kunden"
}
},
required: ["productCode", "quantity", "customerType", "region"]
},
execute: async (params) => {
// SpreadAPI aufrufen
const response = await fetch('https://api.spreadapi.io/v1/services/pricing-model/execute', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SPREADAPI_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ inputs: params })
});
const result = await response.json();
return result.outputs;
}
};
// Den KI-Agent erstellen
const model = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0
});
const tools = [pricingTool];
const modelWithTools = model.bind({ tools });Agent-Logik implementieren
class CustomerServiceAgent {
constructor(model, tools) {
this.model = model;
this.tools = tools;
this.conversation = [];
}
async respond(userMessage) {
// Benutzernachricht zum Gespräch hinzufügen
this.conversation.push({
role: 'user',
content: userMessage
});
// KI-Antwort mit möglichen Tool-Aufrufen erhalten
const response = await this.model.invoke(this.conversation);
// Tool-Aufrufe behandeln
if (response.tool_calls && response.tool_calls.length > 0) {
for (const toolCall of response.tool_calls) {
const tool = this.tools.find(t => t.name === toolCall.name);
if (tool) {
// Excel-Berechnung ausführen
const result = await tool.execute(toolCall.arguments);
// Tool-Ergebnis zum Gespräch hinzufügen
this.conversation.push({
role: 'tool',
content: JSON.stringify(result),
tool_call_id: toolCall.id
});
}
}
// Endgültige Antwort nach Tool-Ausführung erhalten
const finalResponse = await this.model.invoke(this.conversation);
this.conversation.push({
role: 'assistant',
content: finalResponse.content
});
return finalResponse.content;
}
// Keine Tool-Aufrufe erforderlich
this.conversation.push({
role: 'assistant',
content: response.content
});
return response.content;
}
}Schritt 3: Produktionsreife Muster
Muster 1: Multi-Tool-Agent
// Mehrere Excel-basierte Tools hinzufügen
const tools = [
{
name: "calculate_pricing",
description: "Produktpreise und Rabatte berechnen",
spreadapiService: "pricing-model",
execute: spreadapiExecutor("pricing-model")
},
{
name: "check_inventory",
description: "Produktverfügbarkeit und Lieferzeiten prüfen",
spreadapiService: "inventory-tracker",
execute: spreadapiExecutor("inventory-tracker")
},
{
name: "calculate_shipping",
description: "Versandkosten und Liefertermine berechnen",
spreadapiService: "logistics-calculator",
execute: spreadapiExecutor("logistics-calculator")
}
];
// Hilfsfunktion für SpreadAPI-Ausführung
function spreadapiExecutor(serviceName) {
return async (params) => {
const response = await fetch(
`https://api.spreadapi.io/v1/services/${serviceName}/execute`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SPREADAPI_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ inputs: params })
}
);
if (!response.ok) {
throw new Error(`Excel-Berechnung fehlgeschlagen: ${response.statusText}`);
}
const result = await response.json();
return result.outputs;
};
}Muster 2: Kontextbewusster Agent
class ContextAwareAgent {
constructor() {
this.customerContext = {};
this.calculationCache = new Map();
}
async handleQuery(query, customerId) {
// Kundenkontext laden
if (!this.customerContext[customerId]) {
this.customerContext[customerId] = await this.loadCustomerData(customerId);
}
const context = this.customerContext[customerId];
// Prompt mit Kontext erweitern
const enhancedPrompt = `
Kundeninformationen:
- Typ: ${context.customerType}
- Region: ${context.region}
- Kaufhistorie: ${context.totalPurchases} Bestellungen
Benutzeranfrage: ${query}
Anweisungen:
- Verwenden Sie das calculate_pricing-Tool für alle Preisangebote
- Wenden Sie automatisch den entsprechenden Kundentyp an
- Berücksichtigen Sie deren Region für Versandberechnungen
`;
return await this.respond(enhancedPrompt);
}
async loadCustomerData(customerId) {
// Aus Ihrer Datenbank laden
return {
customerType: 'enterprise',
region: 'US',
totalPurchases: 47
};
}
}Muster 3: Validierung und Fehlerbehandlung
class RobustAgent {
async executeToolSafely(tool, params) {
try {
// Eingaben vor Übertragung an Excel validieren
const validation = this.validateInputs(tool.name, params);
if (!validation.valid) {
return {
error: `Ungültige Eingabe: ${validation.message}`,
suggestion: validation.suggestion
};
}
// Zuerst Cache prüfen
const cacheKey = `${tool.name}:${JSON.stringify(params)}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
// Mit Timeout ausführen
const result = await Promise.race([
tool.execute(params),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Berechnungs-Timeout')), 5000)
)
]);
// Erfolgreiche Ergebnisse cachen
this.cache.set(cacheKey, result);
// Ausgabe validieren
if (result.finalPrice < 0) {
return {
error: 'Ungültiges Berechnungsergebnis',
suggestion: 'Bitte prüfen Sie Produktcode und Menge'
};
}
return result;
} catch (error) {
console.error('Tool-Ausführung fehlgeschlagen:', error);
// Fallback-Antwort
return {
error: 'Berechnung momentan nicht möglich',
suggestion: 'Bitte versuchen Sie es erneut oder kontaktieren Sie den Support',
reference: error.message
};
}
}
validateInputs(toolName, params) {
if (toolName === 'calculate_pricing') {
if (params.quantity < 1) {
return {
valid: false,
message: 'Menge muss mindestens 1 betragen',
suggestion: 'Bitte geben Sie eine gültige Menge an'
};
}
if (!params.productCode.match(/^[A-Z]{3}-\d{3}$/)) {
return {
valid: false,
message: 'Ungültiges Produktcode-Format',
suggestion: 'Produktcodes sollten wie ABC-123 aussehen'
};
}
}
return { valid: true };
}
}Schritt 4: Erweiterte Agent-Fähigkeiten
Fähigkeit 1: Mehrstufige Berechnungen
const complexWorkflowTool = {
name: "quote_with_options",
description: "Vollständiges Angebot mit mehreren Produktoptionen erstellen",
execute: async (params) => {
const { products, customerType, region } = params;
// Preisberechnung für jedes Produkt
const quotes = await Promise.all(
products.map(async (product) => {
const pricing = await spreadapiExecutor('pricing-model')({
productCode: product.code,
quantity: product.quantity,
customerType,
region
});
const shipping = await spreadapiExecutor('logistics-calculator')({
productCode: product.code,
quantity: product.quantity,
region,
expedited: product.expedited || false
});
return {
product: product.code,
quantity: product.quantity,
pricing,
shipping,
total: pricing.finalPrice + shipping.cost
};
})
);
// Bundle-Rabatt berechnen, falls anwendbar
if (quotes.length > 1) {
const bundleResult = await spreadapiExecutor('bundle-calculator')({
products: products.map(p => p.code),
quantities: products.map(p => p.quantity),
customerType
});
return {
individualQuotes: quotes,
bundleDiscount: bundleResult.discount,
bundleTotal: bundleResult.total
};
}
return { quotes };
}
};Fähigkeit 2: Erklärungen und Begründungen
class ExplainableAgent {
async respondWithExplanation(query) {
const response = await this.model.invoke([
{
role: 'system',
content: `Sie sind ein hilfreicher Kundenservice-Agent.
Bei der Verwendung von Preis-Tools erklären Sie immer:
1. Welche Faktoren den Preis beeinflusst haben
2. Welche Rabatte angewendet wurden
3. Warum dies die beste Option für den Kunden ist`
},
{
role: 'user',
content: query
}
]);
// Tool-Aufrufe verarbeiten und Erklärungen hinzufügen
if (response.tool_calls) {
const explanations = [];
for (const toolCall of response.tool_calls) {
const result = await this.executeTool(toolCall);
// Erklärung basierend auf Ergebnissen generieren
if (toolCall.name === 'calculate_pricing') {
const discount = result.basePrice - result.finalPrice;
const discountPercent = (discount / result.basePrice * 100).toFixed(1);
explanations.push({
calculation: toolCall.name,
explanation: `
Grundpreis: €${result.basePrice}
${discount > 0 ? `Rabatt angewendet: €${discount} (${discountPercent}%)` : 'Kein Rabatt anwendbar'}
Endpreis: €${result.finalPrice}
Lieferung bis: ${result.deliveryDate}
`
});
}
}
// Endgültige Antwort mit Erklärungen erhalten
const finalResponse = await this.model.invoke([
...this.conversation,
{
role: 'system',
content: `Fügen Sie diese Berechnungsdetails in Ihre Antwort ein: ${JSON.stringify(explanations)}`
}
]);
return finalResponse.content;
}
return response.content;
}
}Fähigkeit 3: Szenario-Vergleich
const scenarioTool = {
name: "compare_scenarios",
description: "Verschiedene Kaufszenarien vergleichen, um die beste Option zu finden",
execute: async (params) => {
const scenarios = [
{
name: "Einzelkauf",
params: {
quantity: params.quantity,
customerType: params.customerType
}
},
{
name: "Großeinkauf",
params: {
quantity: params.quantity * 3,
customerType: params.customerType
}
},
{
name: "Jahresvertrag",
params: {
quantity: params.quantity * 12,
customerType: 'enterprise' // Automatische Aufwertung
}
}
];
const results = await Promise.all(
scenarios.map(async (scenario) => {
const pricing = await spreadapiExecutor('pricing-model')({
...params,
...scenario.params
});
return {
scenario: scenario.name,
totalQuantity: scenario.params.quantity,
unitPrice: pricing.finalPrice / scenario.params.quantity,
totalPrice: pricing.finalPrice,
savings: (params.quantity * (pricing.basePrice / scenario.params.quantity)) - pricing.finalPrice
};
})
);
// Beste Option finden
const bestOption = results.reduce((best, current) =>
current.unitPrice < best.unitPrice ? current : best
);
return {
scenarios: results,
recommendation: bestOption,
potentialSavings: results[0].totalPrice - bestOption.totalPrice
};
}
};Schritt 5: Deployment und Monitoring
Produktionskonfiguration
// config/agent.js
export const agentConfig = {
model: {
name: process.env.MODEL_NAME || 'gpt-4',
temperature: 0,
maxTokens: 1000,
timeout: 30000
},
spreadapi: {
baseUrl: process.env.SPREADAPI_URL || 'https://api.spreadapi.io/v1',
apiKey: process.env.SPREADAPI_KEY,
timeout: 5000,
retries: 3
},
caching: {
ttl: 300, // 5 Minuten
maxSize: 1000
},
monitoring: {
logLevel: process.env.LOG_LEVEL || 'info',
metricsEnabled: true,
tracingEnabled: process.env.NODE_ENV === 'production'
}
};Monitoring und Analytics
class MonitoredAgent {
constructor(config) {
this.metrics = {
totalRequests: 0,
toolCalls: {},
errors: {},
responseTime: []
};
}
async handleRequest(query) {
const startTime = Date.now();
const requestId = generateRequestId();
try {
console.log(`[${requestId}] Verarbeite Anfrage:`, query);
const response = await this.agent.respond(query);
const duration = Date.now() - startTime;
this.metrics.responseTime.push(duration);
this.metrics.totalRequests++;
console.log(`[${requestId}] Abgeschlossen in ${duration}ms`);
// An Analytics senden
await this.sendAnalytics({
requestId,
duration,
toolsUsed: this.agent.lastToolCalls,
success: true
});
return response;
} catch (error) {
const errorType = error.name || 'Unbekannt';
this.metrics.errors[errorType] = (this.metrics.errors[errorType] || 0) + 1;
console.error(`[${requestId}] Fehler:`, error);
await this.sendAnalytics({
requestId,
error: error.message,
success: false
});
throw error;
}
}
getMetrics() {
const avgResponseTime =
this.metrics.responseTime.reduce((a, b) => a + b, 0) /
this.metrics.responseTime.length;
return {
totalRequests: this.metrics.totalRequests,
averageResponseTime: avgResponseTime,
toolUsage: this.metrics.toolCalls,
errorRate: Object.values(this.metrics.errors).reduce((a, b) => a + b, 0) /
this.metrics.totalRequests
};
}
}Häufige Fallstricke und Lösungen
Fallstrick 1: Den Agent überlasten
// Schlecht: Dem Agent zu viel Freiheit geben
const badPrompt = "Helfen Sie dem Kunden bei allem, was er braucht";
// Gut: Klare Grenzen und Fähigkeiten
const goodPrompt = `Sie sind ein Kundenservice-Agent, spezialisiert auf:
1. Produktpreise (verwenden Sie das calculate_pricing-Tool)
2. Lagerverfügbarkeit (verwenden Sie das check_inventory-Tool)
3. Versandschätzungen (verwenden Sie das calculate_shipping-Tool)
Für andere Anfragen erklären Sie höflich, womit Sie helfen können.`;Fallstrick 2: Excel-Fehler nicht behandeln
// Robuste Fehlerbehandlung
const toolWithErrorHandling = {
execute: async (params) => {
try {
const result = await spreadapiCall(params);
// Excel-Ergebnisse validieren
if (result.outputs.error) {
return {
success: false,
error: 'Berechnungsfehler in Excel',
details: result.outputs.error,
suggestion: 'Bitte Produktcode prüfen und erneut versuchen'
};
}
return { success: true, ...result.outputs };
} catch (error) {
if (error.status === 422) {
return {
success: false,
error: 'Ungültige Eingabeparameter',
suggestion: 'Bitte prüfen Sie Ihr Produktcode-Format'
};
}
throw error; // Unerwartete Fehler erneut werfen
}
}
};Fallstrick 3: Performance ignorieren
// Performance-Optimierung
class OptimizedAgent {
constructor() {
this.cache = new LRUCache({ max: 500, ttl: 1000 * 60 * 5 });
this.batchQueue = [];
this.batchTimer = null;
}
async calculatePricing(params) {
// Zuerst Cache prüfen
const cacheKey = JSON.stringify(params);
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
// Ähnliche Anfragen stapeln
return new Promise((resolve) => {
this.batchQueue.push({ params, resolve });
if (!this.batchTimer) {
this.batchTimer = setTimeout(() => this.processBatch(), 50);
}
});
}
async processBatch() {
const batch = this.batchQueue.splice(0, 50); // Bis zu 50 auf einmal verarbeiten
const results = await spreadapiExecutor('pricing-model').batch(
batch.map(item => item.params)
);
results.forEach((result, index) => {
const { params, resolve } = batch[index];
this.cache.set(JSON.stringify(params), result);
resolve(result);
});
this.batchTimer = null;
}
}Ihren Agent testen
// test/agent.test.js
describe('Kundenservice-Agent', () => {
let agent;
beforeEach(() => {
agent = new CustomerServiceAgent();
});
test('sollte Preise genau berechnen', async () => {
const response = await agent.respond(
"Wie ist der Preis für 100 Einheiten von PRO-001 für einen Enterprise-Kunden in den USA?"
);
expect(response).toContain('Preis');
expect(response).toMatch(/€[0-9.,]+/);
});
test('sollte ungültige Produktcodes behandeln', async () => {
const response = await agent.respond(
"Preis für Produkt XYZ"
);
expect(response).toContain('gültiger Produktcode');
});
test('sollte Szenarien vergleichen, wenn gefragt', async () => {
const response = await agent.respond(
"Soll ich jetzt 10 Einheiten kaufen oder auf eine Großbestellung warten?"
);
expect(response).toContain('Szenario');
expect(response).toContain('Empfehlung');
});
});Go-Live-Checkliste
- [ ] Excel-Modelle zu SpreadAPI hochgeladen
- [ ] Input/Output-Mappings definiert
- [ ] API-Schlüssel sicher gespeichert
- [ ] Agent-System-Prompt verfeinert
- [ ] Tool-Beschreibungen klar und spezifisch
- [ ] Fehlerbehandlung implementiert
- [ ] Caching-Strategie vorhanden
- [ ] Monitoring und Logging konfiguriert
- [ ] Rate Limiting aktiviert
- [ ] Testabdeckung > 80%
- [ ] Last-Tests abgeschlossen
- [ ] Fallback-Antworten definiert
- [ ] Dokumentation aktualisiert
Nächste Schritte
- Einfach anfangen: Ein Excel-Modell, ein Tool, einfacher Agent
- Intelligenz hinzufügen: Kontextbewusstsein, mehrstufige Workflows
- Hochskalieren: Mehrere Modelle, Caching, Monitoring
- Optimieren: Performance-Tuning, Kostenoptimierung
Bereit, Ihren KI-Agent zu entwickeln? Beginnen Sie mit SpreadAPI
Fragen? Beispiele? Schreiben Sie uns an hello@airrange.io
Verwandte Artikel
Entdecken Sie weitere Excel-API- und KI-Integrations-Anleitungen: