Lessons from Building a Production RAG System: Data Formatting and Prompt Engineering

credal · Tech · 2023 · source Agentic: no · promotional bias: med · source-backed · extracted with prompt 0.5.6 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Enterprise RAG over complex corporate documents

Credal needed production-grade RAG and routing systems for real corporate documents where naive loaders, vector search, and prompts failed on footnotes, tables, summaries, date reasoning, structured output, and cost-sensitive Slack routing. The core constraint was that LLM attention is limited, so both data representation and prompts had to focus the model on the hardest part of each task.

Constraints:

Architecture

Credal built custom RAG and prompt workflows that restructure documents before retrieval, enrich sections with LLM-generated metadata tags, route summary questions to summary-like sections, inline footnotes near references, convert tables to CSV, and split multi-step prompt work into focused sequential calls. For Slack AI experts, GPT-3.5 first concentrates on matching the user message to the right expert, then a second GPT-3.5 formatting call repairs JSON when needed. Human experts define domain tags and can verify generated answers.

Diagram confidence: reconstructed (reconstructed from prose).

flowchart LR
  docs["Corporate document corpus"] --> format["Document formatting pipeline"]
  docs --> tags["Metadata tagging pipeline"]
  curator["Human tag curator"] --> tags
  format --> vector["Vector store"]
  tags --> filter["Tag pre-filter"]
  filter --> vector
  vector --> answer["Answering model"]
  slack["Slack expert router"] --> experts["Expert descriptions"]
  slack --> repair["JSON repair call"]
  repair --> slack
  slack --> domain["Domain-specific AI experts"]
  domain --> answer
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
Corporate document corpus Long and complex real-world documents from enterprise customers, including footnotes, tables, and many user query styles. Document formatting pipeline, Metadata tagging pipeline
Document formatting pipeline Custom preprocessing that inlines footnotes and converts tables to LLM-readable formats such as CSV. Corporate document corpus, Vector store
Metadata tagging pipeline LLM-powered ingestion step that labels document sections with high-level content and domain-specific concepts. Corporate document corpus, Human tag curator, Tag pre-filter
Human tag curator Domain expert who defines or curates relevant tags for document types and use cases. Metadata tagging pipeline
Vector store Stores embeddings for formatted sections and supports semantic retrieval. Document formatting pipeline, Tag pre-filter, Answering model
Tag pre-filter Uses generated tags to narrow search to relevant section types before semantic search. Metadata tagging pipeline, Vector store
Answering model LLM that answers using retrieved and properly formatted context. Vector store, Slack expert router
Slack expert router GPT-3.5 triager that routes questions to the right domain-specific AI expert. Expert descriptions, JSON repair call, Domain-specific AI experts
Expert descriptions Names, descriptions, and routing instructions used by the triager to decide whether an expert should answer. Slack expert router
JSON repair call Second GPT-3.5 call used only when the first routing response is correct but malformed. Slack expert router
Domain-specific AI experts Slack/API experts that answer using relevant data after routing. Slack expert router, Answering model

Data flow

Corporate documents are ingested through custom formatting rather than naive loaders. Footnotes are inserted at the citation point, tables are converted to CSV, and sections receive LLM-generated tags such as summary/exposition or customer/product-feature concepts. At query time, tags pre-filter the relevant sections before semantic search. The retrieved context goes to an answer model. For Slack AI experts, an LLM triager compares the user message to expert descriptions with examples occupying the bulk of the prompt; if the JSON is malformed, a second GPT-3.5 call focuses only on formatting.

4 supporting quotes
“we had to carefully format data, before sending it from company systems to an LLM”article, stated
“we used LLMs to calculate metadata tags for each document or even each section of each document. Those can then be used in the search”article, stated
“when representing a footnoted document to an LLM in a RAG system, you want to insert the details of the footnote in the same place as the quote.”article, stated
“when the first call failed a JSON parsing check, we’d make a second GPT-3.5 call that just focused on JSON formatting.”article, stated

Why this architecture

Credal rejects naive RAG because embedding search cannot infer semantic relationships that live in document structure, such as footnotes attached to citations or tables with implicit rows and columns. Metadata tags give retrieval a way to find summary sections that do not mention the user's words. Prompt splitting keeps GPT-3.5 focused on the high-value classification task while a second cheap call handles formatting if needed. The design follows the principle that model attention is scarce and should be spent on the hard part of the task.

4 supporting quotes
“AI models have limited attention. The hardest prompts either require the LLM to perform multiple logical steps, or they have lots of potentially relevant context.”article, stated
“the document contains no structured indicator of which parts are high level summaries of the overall argument.”article, stated
“There’s no realistic way for the embeddings (embeddings are the technical term for the numerical representation of text data stored in a vector store)”article, stated
“Good prompts focus on the hardest part of the task”article, stated

Models used: GPT-3.5 · GPT-4 · GPT-4-32k · Claude · Claude 2 · Pinecone vector store · LangChain components

Scale

Alternatives considered (roads not taken)

Use out-of-the-box LangChain document loaders and parsers

Rejected because: Credal says standard loaders lose structure such as footnote placement and table layout, and LangChain's structured parser distracted GPT-3.5.

“Contained within both of these ideas was the realization that we could not rely on libraries like LangChain”article, stated
“The LangChain Document parser puts the footnotes all together at the end”article, stated

Use whole-document context for summary questions

Rejected because: Claude's context window can work for one document but is expensive and does not scale to many documents or very large corpora.

“If we use Claude on the entire document, each question could cost more than $1 to answer.”article, stated
“if we’re dealing with 100 papers, one long book or in one real-world case, 4000 written letters, reading the entire text isn’t an option.”article, stated

Use LangChain StructuredOutputParser in the triager prompt

Rejected because: The formatting instructions consumed attention and dropped GPT-3.5 matching accuracy to 50%.

“the structured formatting trick was really great for getting the triager to respond in structured data, but it also distracted GPT 3.5 from the hard part”article, stated
“GPT-3.5 picked the right choice only 50% of the time, even with just one expert in the channel.”article, stated

Use a single GPT-4 call for routing and formatting

Rejected because: Two focused GPT-3.5 calls were faster and cheaper when JSON repair was needed.

“Even when we did need two calls, 2x GPT-3.5 calls still worked out both quicker and much cheaper than one call to GPT 4.”article, stated

Patterns

rag-retrieval (retrieval)

Credal retrieves focused document sections for user questions, but augments naive vector search with formatting and metadata tags.

“Instead we want to first retrieve the part of the document relevant to answer this question, and then have the LLM use that part to answer the question.”article, stated
“This approach is called “RAG”, or Retrieval Augmented Generation.”article, stated

data-quality-loop (ingestion)

Credal restructures footnotes, tables, and section metadata before retrieval so the LLM receives semantically meaningful context.

“Taking time to format your data in a way that the LLM will understand is essential for high quality performance on the last 30-40% of questions.”article, stated
“Tagging documents or document sections with the key concepts or ideas that they contain”article, stated

human-in-the-loop-gate (data-curation)

Human experts define the important tags and can verify model outputs, while LLMs perform scalable reading and tagging.

“If the human expert can tell us the important concepts to look out for, the LLM can identify which parts of each document”article, stated
“if needed coming back to the human for verification.”article, stated

prompt-chaining (prompting)

Credal splits matching and JSON formatting into sequential GPT-3.5 calls with a parsing check between them.

“Sequential prompts work better than single prompts doing multiple things, especially if you can have some kind of accuracy check in between”article, stated
“when the first call failed a JSON parsing check, we’d make a second GPT-3.5 call that just focused on JSON formatting.”article, stated

structured-output-contract (integration)

The AI-expert router must return parseable structured data so code can decide which expert to call.

“We use the response from the LLM triager (which is itself an LLM) to determine which AI expert to call in code.”article, stated
“So we need the triager’s response in a structured form.”article, stated

cost-aware-routing (model-selection)

Credal uses GPT-3.5 and focused prompt design for high-volume Slack routing because GPT-4 on every message would be too expensive and slow.

“we deliberately use GPT-3.5 to avoid massive costs and latency.”article, stated
“Even when we did need two calls, 2x GPT-3.5 calls still worked out both quicker and much cheaper than one call to GPT 4.”article, stated

Tradeoffs

Summary retrieval strategy

Chose LLM-generated metadata tags and pre-filtered RAG over plain semantic search over the whole document.

Rationale: The relevant summary section may not contain the words in the user's query, so tags identify the right kind of section before search.

“the part of the paper that presents the main thesis never mentions the words “main thesis”.”article, stated
“when a user question comes in, we can use those tags to pre-filter the text to the sections actually relevant to the user.”article, stated

Prompt design for routing

Chose few-shot examples and core matching instructions as most of the prompt over long structured-format instructions.

Rationale: The routing decision was the hard part; JSON formatting mattered but should not consume attention needed for matching.

“we stripped out all of the Langchain output formatting instructions”article, stated
“making half of the entire prompt just the example cases, and using the other half for the core instructions”article, stated

Model cost strategy

Chose focused GPT-3.5 calls with a second formatting call when needed over one GPT-4 call for every Slack message.

Rationale: GPT-3.5 with focused prompting and a repair call was faster and cheaper while avoiding GPT-4 cost on high-volume channels.

“we deliberately use GPT-3.5 to avoid massive costs and latency.”article, stated
“2x GPT-3.5 calls still worked out both quicker and much cheaper than one call to GPT 4.”article, stated

Gotchas (what bit them)

Embedding search cannot recover relationships that were lost in parsing.

Root cause: Footnote content was moved away from the quoted text, so author/citation information was not semantically near the question target.

Resolution: Inline footnote details where the reference appears before indexing or sending context to the LLM.

“the author’s name and the book they wrote isn’t semantically similar to the quotation itself, and so the two will almost never show up together in search results.”article, stated
“insert the details of the footnote in the same place as the quote.”article, stated

Bad table formatting causes reasoning failures even with strong models.

Root cause: Raw parsed tables collapse rows and columns into confusing text, making date and count reasoning unreliable.

Resolution: Represent tables clearly, such as converting them to CSV before model input.

“The LangChain Google Doc parser transforms it into this:”article, stated
“if we instead represent the table more clearly (by turning the table itself into a little CSV inside the document), we can finally get an accurate answer”article, stated

Formatting instructions can steal model attention from the actual task.

Root cause: StructuredOutputParser instructions took 10-20 lines and competed with examples for GPT-3.5's limited attention.

Resolution: Remove heavy formatting instructions, embed JSON naturally in examples, and repair malformed JSON in a second focused call.

“This would end up becoming about 10-20 lines of instructions about how to output the data as JSON”article, stated
“we had to remove the LangChain tool for getting the output as structured data”article, stated

Full-context summarization can work for one document but fails economically and structurally at enterprise scale.

Root cause: Large context windows are finite and expensive, and enterprise corpora include thousands of documents and huge systems like Drive, Confluence, Slack, and SharePoint.

Resolution: Use RAG plus per-use-case data representation and prompting rather than reading entire corpora.

“even those context windows are very finite relative to some of the legal contracts or spreadsheets out there”article, stated
“forget about the entire corpus of a 1,000+ person Enterprise’s GDrive, Confluence, Slack, Sharepoint and more.”article, stated

Evaluation

Credal reports empirical evaluation through answer failures on example questions, model comparisons on table/date reasoning, Slack triager accuracy targets, JSON parsing checks, and human verification for answers where needed.

Metrics: 95%+ routing accuracy target · 80% precision and 95% recall target for the triager · 50% GPT-3.5 accuracy under the structured-output prompt · JSON parse success · answer correctness on summary, citation, and table questions · cost and latency per routing call

3 supporting quotes
“we needed an initial step that could triage the user question to the right AI expert with 95%+ accuracy”article, stated
“[4.] For nerds - we were aiming for 80% precision and 95% recall”article, stated
“GPT-3.5 picked the right choice only 50% of the time, even with just one expert in the channel.”article, stated

Outcomes

The lessons come from 250k+ LLM calls, 100k corporate documents, enterprise customers with thousands of employees, and high-volume Slack-channel routing.

3 supporting quotes
“we turned a question that is impossible for the LLM to answer, into one that is dead simple!”article, stated
“we can use those tags to pre-filter the text to the sections actually relevant to the user.”article, stated
“In short, we found that when you’re building a demo that only needs to work on small amounts of highly controlled data, you can be pretty naive”article, stated