KOBAI: KI-basiertes Dokumentenmanagement bei Schott Pharma

KOBAI: KI-basiertes Dokumentenmanagement bei Schott Pharma

Ausgezeichnet mit dem Digital Game-changer Award 2024

Die Digitalisierung der Pharmaindustrie stellt besondere Anforderungen an Datenschutz und Compliance. Mit KOBAI haben wir eine innovative KI-Lösung entwickelt, die diese Herausforderungen meistert und gleichzeitig die Effizienz drastisch steigert.

Projektherausforderung

Schott Pharma, ein führender Hersteller von Pharmaverpackungen, stand vor folgenden Herausforderungen:

Ausgangssituation

  • Dokumentenvolumen: >50.000 technische Dokumente
  • Suchzeit: Durchschnittlich 45 Minuten pro Anfrage
  • Compliance: Strenge DSGVO und FDA-Anforderungen
  • Vertraulichkeit: Keine Cloud-Lösungen erlaubt
  • Mehrsprachigkeit: Deutsch, Englisch, weitere EU-Sprachen

Geschäftliche Auswirkungen

  • Verzögerungen in der Produktentwicklung
  • Hohe Personalkosten für Dokumentensuche
  • Risiko von Compliance-Verstössen
  • Ineffiziente Wissensverteilung

Lösungsansatz: KOBAI

KOBAI (Knowledge Organization with Business AI) ist eine vollständig lokale KI-Lösung, die auf Offline-Large Language Models basiert.

Kernkomponenten

1. Lokale LLM-Integration

# LM Studio Integration
from openai import OpenAI

class LocalLLMClient:
    def __init__(self, base_url="http://localhost:1234/v1"):
        self.client = OpenAI(
            base_url=base_url,
            api_key="lm-studio"  # Dummy-Key für lokale Instanz
        )
    
    def query_documents(self, question, context):
        response = self.client.chat.completions.create(
            model="microsoft/DialoGPT-medium",  # Lokales Modell
            messages=[
                {"role": "system", "content": "Du bist ein Experte für Pharmadokumentation."},
                {"role": "user", "content": f"Kontext: {context}nnFrage: {question}"}
            ],
            temperature=0.1,  # Niedrige Temperatur für präzise Antworten
            max_tokens=500
        )
        return response.choices[0].message.content

2. Dokumenten-Indexierung

// C# Backend für Dokumentenverarbeitung
public class DocumentProcessor
{
    private readonly IVectorDatabase _vectorDb;
    private readonly ITextExtractor _textExtractor;
    
    public async Task<ProcessingResult> ProcessDocument(DocumentInfo doc)
    {
        try
        {
            // Text extrahieren
            var extractedText = await _textExtractor.ExtractAsync(doc.FilePath);
            
            // Chunking für bessere Verarbeitung
            var chunks = SplitIntoChunks(extractedText, maxChunkSize: 1000);
            
            // Embeddings generieren (lokal)
            var embeddings = await GenerateEmbeddings(chunks);
            
            // In Vektordatenbank speichern
            await _vectorDb.StoreAsync(doc.Id, embeddings, chunks);
            
            return new ProcessingResult { Success = true, ChunksProcessed = chunks.Count };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Fehler bei Dokumentenverarbeitung: {DocumentId}", doc.Id);
            return new ProcessingResult { Success = false, Error = ex.Message };
        }
    }
    
    private List<string> SplitIntoChunks(string text, int maxChunkSize)
    {
        var chunks = new List<string>();
        var sentences = text.Split('.', StringSplitOptions.RemoveEmptyEntries);
        var currentChunk = new StringBuilder();
        
        foreach (var sentence in sentences)
        {
            if (currentChunk.Length + sentence.Length > maxChunkSize)
            {
                if (currentChunk.Length > 0)
                {
                    chunks.Add(currentChunk.ToString().Trim());
                    currentChunk.Clear();
                }
            }
            currentChunk.Append(sentence + ". ");
        }
        
        if (currentChunk.Length > 0)
        {
            chunks.Add(currentChunk.ToString().Trim());
        }
        
        return chunks;
    }
}

3. Semantic Search Engine

public class SemanticSearchEngine
{
    private readonly IVectorDatabase _vectorDb;
    private readonly LocalLLMClient _llmClient;
    
    public async Task<SearchResult> SearchAsync(string query, SearchOptions options)
    {
        // Query-Embedding generieren
        var queryEmbedding = await GenerateQueryEmbedding(query);
        
        // Ähnliche Dokumente finden
        var similarChunks = await _vectorDb.FindSimilarAsync(
            queryEmbedding, 
            topK: options.MaxResults,
            threshold: options.SimilarityThreshold
        );
        
        // Kontext für LLM aufbauen
        var context = BuildContext(similarChunks);
        
        // LLM-Antwort generieren
        var llmResponse = await _llmClient.QueryDocuments(query, context);
        
        return new SearchResult
        {
            Answer = llmResponse,
            SourceDocuments = similarChunks.Select(c => c.DocumentInfo).ToList(),
            Confidence = CalculateConfidence(similarChunks),
            ProcessingTime = stopwatch.ElapsedMilliseconds
        };
    }
}

Technische Architektur

System-Übersicht

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Web Frontend  │────│   C# Backend     │────│  LM Studio      │
│   - React       │    │   - .NET 8       │    │  - Offline LLM  │
│   - TypeScript  │    │   - Entity FW    │    │  - Local API    │
└─────────────────┘    └──────────────────┘    └─────────────────┘
         │                        │                        │
         │                        │                        │
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   User Auth     │    │  Vector Database │    │  Document Store │
│   - Active Dir  │    │  - Chroma DB     │    │  - File System  │
│   - LDAP        │    │  - Embeddings    │    │  - Metadata DB  │
└─────────────────┘    └──────────────────┘    └─────────────────┘

Sicherheitsarchitektur

Datenschutz-Features

public class SecurityManager
{
    public async Task<bool> ValidateAccess(User user, Document document)
    {
        // Rollenbasierte Zugriffskontrolle
        var userRoles = await GetUserRoles(user.Id);
        var requiredRoles = document.AccessRequirements;
        
        if (!userRoles.Any(r => requiredRoles.Contains(r)))
        {
            await LogAccessDenied(user.Id, document.Id, "Insufficient roles");
            return false;
        }
        
        // Abteilungsbasierte Filterung
        if (document.Department != null && user.Department != document.Department)
        {
            await LogAccessDenied(user.Id, document.Id, "Department mismatch");
            return false;
        }
        
        // Audit-Log
        await LogDocumentAccess(user.Id, document.Id, DateTime.UtcNow);
        
        return true;
    }
    
    public string EncryptSensitiveData(string data)
    {
        using var aes = Aes.Create();
        aes.Key = GetEncryptionKey();
        aes.IV = GenerateIV();
        
        using var encryptor = aes.CreateEncryptor();
        var dataBytes = Encoding.UTF8.GetBytes(data);
        var encryptedBytes = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length);
        
        return Convert.ToBase64String(encryptedBytes);
    }
}

Implementation Details

Frontend-Entwicklung

// React-Komponente für intelligente Suche
interface SearchComponentProps {
  onResultsFound: (results: SearchResult[]) => void;
}

const IntelligentSearch: React.FC<SearchComponentProps> = ({ onResultsFound }) => {
  const [query, setQuery] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [suggestions, setSuggestions] = useState<string[]>([]);
  
  const handleSearch = async () => {
    setIsLoading(true);
    try {
      const response = await fetch('/api/search', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ 
          query, 
          options: {
            maxResults: 10,
            includeMetadata: true,
            similarityThreshold: 0.7
          }
        })
      });
      
      const results = await response.json();
      onResultsFound(results);
    } catch (error) {
      console.error('Search failed:', error);
    } finally {
      setIsLoading(false);
    }
  };
  
  // Auto-Suggest Implementation
  useEffect(() => {
    const debounced = debounce(async (searchTerm: string) => {
      if (searchTerm.length > 2) {
        const suggestions = await fetchSuggestions(searchTerm);
        setSuggestions(suggestions);
      }
    }, 300);
    
    debounced(query);
  }, [query]);
  
  return (
    <div className="search-container">
      <SearchInput 
        value={query}
        onChange={setQuery}
        onSearch={handleSearch}
        suggestions={suggestions}
        isLoading={isLoading}
      />
      <SearchFilters />
      <SearchHistory />
    </div>
  );
};

Performance-Optimierung

public class CacheManager
{
    private readonly IMemoryCache _memoryCache;
    private readonly IDistributedCache _distributedCache;
    
    public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory, TimeSpan expiration)
    {
        // Erst Memory Cache prüfen
        if (_memoryCache.TryGetValue(key, out T cachedValue))
        {
            return cachedValue;
        }
        
        // Dann Distributed Cache
        var distributedValue = await _distributedCache.GetStringAsync(key);
        if (distributedValue != null)
        {
            var deserializedValue = JsonSerializer.Deserialize<T>(distributedValue);
            _memoryCache.Set(key, deserializedValue, TimeSpan.FromMinutes(5));
            return deserializedValue;
        }
        
        // Wert generieren und cachen
        var newValue = await factory();
        var serializedValue = JsonSerializer.Serialize(newValue);
        
        await _distributedCache.SetStringAsync(key, serializedValue, new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = expiration
        });
        
        _memoryCache.Set(key, newValue, TimeSpan.FromMinutes(5));
        
        return newValue;
    }
}

Deployment & Betrieb

Containerisierung

# Dockerfile für KOBAI Backend
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["KOBAI.API/KOBAI.API.csproj", "KOBAI.API/"]
COPY ["KOBAI.Core/KOBAI.Core.csproj", "KOBAI.Core/"]
RUN dotnet restore "KOBAI.API/KOBAI.API.csproj"

COPY . .
WORKDIR "/src/KOBAI.API"
RUN dotnet build "KOBAI.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "KOBAI.API.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

# LM Studio Installation
RUN apt-get update && apt-get install -y 
    curl 
    python3 
    python3-pip

# Lokale LLM-Modelle
COPY models/ /app/models/

ENTRYPOINT ["dotnet", "KOBAI.API.dll"]

Monitoring & Logging

public class ApplicationInsights
{
    private readonly ILogger<ApplicationInsights> _logger;
    private readonly TelemetryClient _telemetryClient;
    
    public void TrackSearchQuery(string query, int resultsCount, long processingTime)
    {
        _telemetryClient.TrackEvent("SearchQuery", new Dictionary<string, string>
        {
            ["Query"] = HashQuery(query), // Anonymisiert
            ["ResultsCount"] = resultsCount.ToString(),
            ["ProcessingTime"] = processingTime.ToString()
        });
        
        _logger.LogInformation("Search completed: {ResultsCount} results in {ProcessingTime}ms", 
                              resultsCount, processingTime);
    }
    
    public void TrackDocumentAccess(string userId, string documentId)
    {
        _telemetryClient.TrackEvent("DocumentAccess", new Dictionary<string, string>
        {
            ["UserId"] = HashUserId(userId),
            ["DocumentType"] = GetDocumentType(documentId)
        });
    }
}

Ergebnisse & Impact

Quantitative Verbesserungen

  • Suchzeit: Von 45 Minuten auf 30 Sekunden (-98.9%)
  • Treffergenauigkeit: 94% relevante Ergebnisse
  • Benutzerakzeptanz: 97% positive Bewertungen
  • Zeitersparnis: 40 Stunden/Woche pro Abteilung
  • ROI: 340% im ersten Jahr

Qualitative Verbesserungen

  • Wissenstransfer: Bessere Verteilung von Expertenwissen
  • Compliance: 100% DSGVO-konform
  • Mitarbeiterzufriedenheit: Weniger Frustration bei der Dokumentensuche
  • Innovation: Schnellere Produktentwicklung durch besseren Informationszugang

Technische KPIs

public class PerformanceMetrics
{
    public class SearchMetrics
    {
        public double AverageResponseTime { get; set; } = 847; // ms
        public double P95ResponseTime { get; set; } = 1200; // ms
        public double AccuracyScore { get; set; } = 0.94;
        public int QueriesPerDay { get; set; } = 1247;
    }
    
    public class SystemMetrics
    {
        public double CpuUtilization { get; set; } = 0.23;
        public double MemoryUtilization { get; set; } = 0.67;
        public double DiskUtilization { get; set; } = 0.45;
        public double Uptime { get; set; } = 0.9998; // 99.98%
    }
}

Auszeichnung: Digital Game-changer Award

KOBAI wurde 2024 mit dem Digital Game-changer Award ausgezeichnet für:

  • Innovation: Erste vollständig lokale KI-Lösung in der Pharmaindustrie
  • Impact: Dramatische Effizienzsteigerung bei höchsten Sicherheitsstandards
  • Skalierbarkeit: Übertragbarkeit auf andere regulierte Industrien
  • Nachhaltigkeit: Reduzierung des CO2-Footprints durch lokale Verarbeitung

Lessons Learned

Technische Erkenntnisse

  1. Lokale LLMs: Ausreichende Qualität für Unternehmenszwecke
  2. Hybrid-Ansatz: Kombination aus Vektor-Suche und LLM optimal
  3. Chunking-Strategien: Entscheidend für Antwortqualität
  4. Caching: Kritisch für Performance bei wiederholten Anfragen

Organisatorische Erkenntnisse

  1. Change Management: Intensive Schulungen notwendig
  2. Stakeholder-Einbindung: Frühe Einbindung aller Abteilungen
  3. Iterative Entwicklung: Agile Methoden auch bei KI-Projekten
  4. Compliance: Frühzeitige Einbindung der Rechtsabteilung

Zukunftsentwicklung

Geplante Features

  • Multimodale Suche: Integration von Bildern und Diagrammen
  • Automatische Zusammenfassungen: KI-generierte Dokumenten-Abstracts
  • Predictive Search: Vorhersage von Informationsbedarf
  • Integration: Anbindung an weitere Unternehmenssysteme

Skalierung

public class ScalingStrategy
{
    public async Task<DeploymentPlan> PlanScaling(ScalingRequirements requirements)
    {
        return new DeploymentPlan
        {
            // Horizontale Skalierung
            AdditionalNodes = CalculateRequiredNodes(requirements.ExpectedLoad),
            
            // Vertikale Skalierung
            ResourceUpgrade = new ResourceUpgrade
            {
                CpuCores = requirements.CpuRequirement,
                MemoryGB = requirements.MemoryRequirement,
                StorageTB = requirements.StorageRequirement
            },
            
            // Geografische Verteilung
            RegionalDeployments = requirements.Regions.Select(r => new RegionalDeployment
            {
                Region = r,
                LocalLLMModel = SelectOptimalModel(r.Language),
                ComplianceRequirements = GetRegionalCompliance(r)
            }).ToList()
        };
    }
}

Fazit

KOBAI demonstriert eindrucksvoll, wie moderne KI-Technologien auch in hochregulierten Umgebungen erfolgreich eingesetzt werden können. Der Schlüssel liegt in der Kombination aus technischer Innovation und strikter Einhaltung von Datenschutz- und Compliance-Anforderungen.

Die Auszeichnung mit dem Digital Game-changer Award bestätigt den innovativen Charakter und den messbaren Geschäftswert der Lösung. KOBAI ist nicht nur ein technischer Erfolg, sondern ein Beispiel dafür, wie KI die Arbeitswelt positiv transformieren kann.

Interessiert an einer ähnlichen KI-Lösung für Ihr Unternehmen? Wir beraten Sie gerne bei der Entwicklung einer massgeschneiderten, DSGVO-konformen KI-Strategie!

Klingt nach Ihrem Projekt?

Schreiben Sie mir oder starten Sie eine unverbindliche Projektanfrage.

Projektanfrage →Kontakt