
AI-Generated Diagrams — PaperBanana
PaperBanana is a reference-driven multi-agent framework that generates publication-quality academic illustrations from method-section prose and figure captions. The two diagrams below were generated at paper-banana.org/#generator using the prompts shown.
To regenerate: paste each Method Section and Figure Caption into the PaperBanana generator, download the result, and save it to quarto/assets/diagrams/ as rag_architecture.svg (or .png) and llm_fallback_chain.svg (or .png).
Related issue: #58.
1 Diagram 1 — RAG Architecture
1.1 Prompt used
We propose a local Retrieval-Augmented Generation (RAG) pipeline built on LangChain, ChromaDB, and Ollama. The system operates in two phases: offline ingestion and online query-response.
During ingestion, source documents (a CSV of Central Bank of Ireland speeches) are loaded and converted into LangChain Document objects, each carrying metadata (date, speaker, title). Documents are then split into overlapping text chunks using a RecursiveCharacterTextSplitter with a chunk size of 1,000 characters and an overlap of 100 characters. Each chunk is embedded using the nomic-embed-text model via Ollama, producing 768-dimensional dense vectors. The resulting embeddings are persisted in a local ChromaDB collection on disk.
At query time, the user’s natural-language question is embedded using the same nomic-embed-text model. A cosine-similarity search over ChromaDB retrieves the top-4 most relevant chunks. These chunks are concatenated into a context block and injected into a ChatPromptTemplate alongside the original question. The prompt is passed to a local Ollama LLM (llama3.2) via a LangChain LCEL chain composed of RunnableParallel and RunnablePassthrough operators. The chain returns both the generated answer and the retrieved source documents in a single pass. A confidence signal is derived from the answer text: if the model returns a sentinel phrase (“I don’t know based on the available speeches.”), the query is flagged as low-confidence and written to a JSONL query log for offline review.
Figure 1: Overview of the local RAG pipeline. Documents are chunked and embedded offline into a ChromaDB vector store. At query time the question is embedded and matched against stored vectors; the top-4 retrieved chunks are combined with the question in a prompt sent to a local Ollama LLM, which generates a grounded answer and a confidence signal.
1.2 Generated illustration
2 Diagram 2 — LLM Provider Fallback Chain
2.1 Prompt used
The system uses a priority-ordered LLM provider selection strategy to ensure availability across different environments. At startup, the get_llm() function in rag/query.py interrogates each provider in sequence and returns the first available instance.
The primary provider is Ollama, a locally-running inference server. The function sends an HTTP request to the Ollama /api/tags endpoint on localhost:11434. If a successful response is received and the required model (llama3.2) is listed, an Ollama LangChain client is returned. No data leaves the local machine in this configuration.
If Ollama is unavailable, the system checks for the presence of an OPENAI_API_KEY environment variable. If found, it instantiates a ChatOpenAI client using the gpt-4o-mini model as the first cloud fallback.
If OpenAI is also unavailable, the function checks for ANTHROPIC_API_KEY and instantiates ChatAnthropic (claude-haiku-4-5) as the second cloud fallback.
Finally, if GOOGLE_API_KEY is present, ChatGoogleGenerativeAI (gemini-1.5-flash) is returned as the third and final cloud fallback.
If no provider is available, the function raises a RuntimeError. This cascading selection ensures the system degrades gracefully across environments ranging from a fully local laptop to a cloud-only CI environment.
Figure 2: LLM provider fallback chain. Ollama (local) is queried first; if unavailable the system falls back through OpenAI, Anthropic, and Google Gemini in order. Each cloud provider requires its API key to be present in the environment. If no provider is reachable a RuntimeError is raised.
2.2 Generated illustration
