Enterprise AI Integration: From Prototype to Production
Enterprise AI Integration: From Prototype to Production
Over the past few years, I have seen many companies struggle with the same uncertainty around AI integration. Almost everyone agrees that AI represents a major transformation. Bringing it into business processes at the right time is now widely treated as a strategic priority.
This often leads to a familiar pattern. Early adopters inside the organisation build prototypes through personal initiative, present them to colleagues and encourage teams to experiment. The first results can be impressive. After a while, however, latency, inaccurate answers, poor alignment with company context, missing access controls and growing token costs become visible. The prototype never becomes a production system, so the project slows down or is cancelled.
The problem is often not that the model is insufficiently capable. The problem is that the system around the model was never designed.
What can AI contribute to an organisation?
Generative AI can search, connect, summarise and generate content across information volumes that an individual user could not realistically read from start to finish for every request. A user should not need to read a thousand pages of policies, procedures or technical documentation to find one relevant answer. A well-designed system retrieves the relevant passages, grounds the answer in those sources and presents verifiable references.
The capability is not limited to text. Multimodal systems can work with text, tables, images, audio and video within the same workflow. Yet real value does not come from model capacity alone. It comes from connecting that capacity to the right business process and the right controls.
The first use case: access to enterprise knowledge
Document processing and access to internal knowledge are often among the first enterprise AI use cases. This is where Retrieval-Augmented Generation, or RAG, enters the picture. The system retrieves source passages relevant to a user’s question and asks the language model to construct its answer from that context.
There is no defensible universal productivity percentage for RAG. Results vary by task, data quality, employee experience and system design. One large field study covering 5,179 customer-support agents found that access to a generative AI assistant increased issues resolved per hour by 14 percent on average, with gains reaching 34 percent among novice and lower-skilled workers.[1] This is not a benchmark that can be applied directly to every RAG project. It does show, however, that AI placed in the right context can accelerate access to knowledge and distribute organisational expertise across a wider workforce.
Why RAG can become a rabbit hole
Chatting with documents looks like a simple demo. Building a reliable enterprise retrieval system is a substantial engineering effort.
Dozens of retrieval patterns are available: dense retrieval, sparse retrieval, hybrid search, metadata filtering, reranking, parent-child retrieval and query expansion are only a few. The right design depends on the data, user questions, accuracy requirements, latency targets and infrastructure budget.
Document processing is the first fragile layer. Structured and unstructured content cannot be parsed in the same way. A text-only PDF is fundamentally different from a document containing tables, footnotes, multi-column layouts, charts, scanned images and complex reading order. PDF is a harder format than it appears. The input data types, parsing strategy, OCR requirements, table extraction and chunking method must therefore be evaluated before the retrieval architecture is selected.
Docling is one of the tools that can process PDFs and other enterprise documents while preserving useful structure. Its official quickstart demonstrates how to convert a document and export it as Markdown.[2]
from pathlib import Path
from docling.document_converter import DocumentConverter
source = Path("documents/company_policy.pdf")
converter = DocumentConverter()
result = converter.convert(source)
markdown = result.document.export_to_markdown()
print(markdown[:1500])This is only a starting point. A production pipeline also needs error handling, file-size limits, OCR fallback, repeated header and footer removal, table validation, checksums, versioning and observability.
Ephemeral chat and a persistent enterprise index are different systems
Once the document pipeline is reliable, the vector database and retrieval lifecycle can be designed.
In an ephemeral chat, files uploaded by a user may be retained only for the active session. An in-memory Chroma collection can be practical for this pattern. Without a persistence parameter, the collection is limited to the process lifecycle.[3]
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
# No persist_directory: the collection lives only for this session.
vector_store = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
collection_name="session_documents",
)
retriever = vector_store.as_retriever(
search_type="mmr",
search_kwargs={"k": 5, "fetch_k": 20},
)A persistent enterprise knowledge base introduces a different set of requirements: index versioning, tenant or department isolation, document-level permissions, metadata filters, deletion and update policies, backups and audit records. The Qdrant example below provides a basic structure for local persistent storage and tenant filtering during retrieval. Qdrant can also run in local mode, as a self-hosted service or as a managed cloud deployment.[4]
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_qdrant import QdrantVectorStore
from qdrant_client import QdrantClient, models
from qdrant_client.http.models import Distance, VectorParams
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
client = QdrantClient(path="./qdrant_data")
collection = "company_knowledge"
if not client.collection_exists(collection):
client.create_collection(
collection_name=collection,
vectors_config=VectorParams(size=384, distance=Distance.COSINE),
)
vector_store = QdrantVectorStore(
client=client,
collection_name=collection,
embedding=embeddings,
)
vector_store.add_documents(chunks)
# Enforce tenant or department isolation during retrieval.
retriever = vector_store.as_retriever(
search_kwargs={
"k": 5,
"filter": models.Filter(
must=[
models.FieldCondition(
key="metadata.tenant_id",
match=models.MatchValue(value="tenant-42"),
)
]
),
}
)The code alone is not a security boundary. A client must not be allowed to supply an arbitrary tenant_id or access filter. Filters should be generated from the authenticated identity and server-side authorisation policy.
Design retrieval as a tool
In an enterprise AI system, it is generally better to expose retrieval through a controlled tool than to give the model unrestricted, direct access to the vector database. The tool defines which index can be searched, how many results can be returned, which metadata filters apply and how sources are represented.
from langchain_core.tools import tool
@tool
def search_company_knowledge(query: str) -> str:
"""Search approved internal sources and return grounded context."""
documents = retriever.invoke(query)
if not documents:
return "No relevant approved source was found."
passages = []
for doc in documents[:5]:
source = doc.metadata.get("source", "unknown")
page = doc.metadata.get("page", "?")
passages.append(
f"[Source: {source}, page: {page}]\n{doc.page_content}"
)
return "\n\n".join(passages)This layer also makes retrieval measurable. Recall@k, precision, answer groundedness, source coverage, latency and cost per answer can be observed independently.
Connecting retrieval to inference
After retrieval is in place, the relevant context must be connected to the inference engine through a wrapper or AI service. This service does more than forward a prompt. It can own authentication, authorisation, model routing, context assembly, token budgets, caching, logging, rate limiting, content controls and citations.
At the interface layer, a self-hosted platform such as OpenWebUI can be used. OpenWebUI can connect to Ollama, vLLM and services that expose an OpenAI-compatible API.[5] This separates the user experience from the enterprise AI service and the selected inference infrastructure.
flowchart TD
U["Employee"] --> UI["Open WebUI"]
UI --> S["AI service<br>OpenAI-compatible API"]
S --> R["Retrieval tool"]
R --> V[("Vector database")]
S --> I["Inference engine"]Conclusion: design a system, not a prototype
Enterprise AI integration does not succeed simply because the organisation selected a powerful model. Value emerges when documents are processed correctly, retrieval quality is measured, access boundaries are enforced, inference costs are controlled and employees receive an experience they can trust.
A compelling demo can be built in days. A production system requires the data, retrieval, security, inference and operational layers to be designed together.
LMXAI helps organisations design and assess enterprise AI architectures end to end—from document pipelines and retrieval quality to inference economics, security and adoption.