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
- Lokale LLMs: Ausreichende Qualität für Unternehmenszwecke
- Hybrid-Ansatz: Kombination aus Vektor-Suche und LLM optimal
- Chunking-Strategien: Entscheidend für Antwortqualität
- Caching: Kritisch für Performance bei wiederholten Anfragen
Organisatorische Erkenntnisse
- Change Management: Intensive Schulungen notwendig
- Stakeholder-Einbindung: Frühe Einbindung aller Abteilungen
- Iterative Entwicklung: Agile Methoden auch bei KI-Projekten
- 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!
