Building a Blog Site with an AI‑Powered RAG Knowledge Base

The author walks through creating a static blog on GitHub Pages using docmd, explains the tool selection, then details the construction of a Retrieval‑Augmented Generation (RAG) knowledge base with llamaIndex, a local Chroma vector store, and optional low‑code dify integration, providing full code snippets and deployment steps.

Java Baker
Java Baker
Java Baker
Building a Blog Site with an AI‑Powered RAG Knowledge Base

The author, a Java developer, built a personal blog and a Retrieval‑Augmented Generation (RAG) knowledge base to enable natural‑language search over dozens of technical articles.

Technology Stack

Static site generator: docmd

Hosting: GitHub Pages

RAG components: llamaIndex , cloud embedding model (via Coding Plan), Chroma local vector store

LLM: cloud large language model (via Coding Plan)

Web UI for queries: Gradio

Blog Site Construction

Among several static site generators (docmd, Jekyll, Hugo, Hexo, MkDocs), docmd was chosen for its zero‑configuration setup, built‑in navigation, full‑text search, Mermaid diagram support, sitemap generation, multilingual capability, and LLM‑friendly output.

Implementation steps:

Install docmd globally: npm install -g @docmd/core Start the development server (optional config):

# Quick preview

docmd dev

# Initialize config for a long‑term project

docmd init

Build the static site: docmd build Upload the generated site directory to a GitHub repository; GitHub Actions automatically builds and deploys the site, avoiding large image files in the repo.

Additional notes: rename directories to hyphenated English names for cleaner URLs and batch‑download markdown images to local paths.

RAG Knowledge Base – Principle

RAG (Retrieval‑Augmented Generation) first splits and vectorizes private documents, stores the vectors in a vector database, then retrieves the most relevant chunks for a user query and feeds both the query and retrieved context to an LLM, reducing hallucinations and narrowing the search space.

Low‑Code Platform Option (dify)

The author evaluated low‑code AI workflow platforms and selected dify for its rich templates and drag‑and‑drop interface. The "Knowledge Base" template already wires together user input, knowledge retrieval, LLM inference, and output. The steps include creating the template app, importing the llms‑full.txt file generated by docmd, configuring the knowledge‑retrieval node, selecting a cloud LLM (with free trial credits), debugging, and optionally embedding the chat widget into the existing blog.

Open‑Source Framework Option (llamaIndex)

Using llamaIndex provides fine‑grained control without the overhead of agent frameworks like LangChain. The workflow consists of two phases: an offline one‑time index build and an online per‑query retrieval.

Offline Index Build

Set global embedding model parameters (API key, model name, endpoint).

Load markdown documents from the blog directory with SimpleDirectoryReader, recursively reading all .md files.

Parse documents into chunks using MarkdownNodeParser, producing hundreds of nodes.

Vectorize nodes via the cloud embedding model (handled internally by llamaIndex) and store the vectors in a persistent Chroma collection to avoid re‑embedding on every run.

# Set embedding model
Settings.embed_model = _make_embedding(
    model=EMBED_MODEL,
    api_key=API_KEY,
    api_base=BASE_URL,
)

# Load documents
reader = SimpleDirectoryReader(
    input_dir=BLOG_DATA_DIR,
    required_exts=[".md"],
    recursive=True,
    filename_as_id=True,
)
documents = reader.load_data(show_progress=True)

# Parse into chunks
parser = MarkdownNodeParser()
nodes = parser.get_nodes_from_documents(documents)

# Store vectors in Chroma
db = chromadb.PersistentClient(path=CHROMA_PATH)
collection = db.get_or_create_collection(COLLECTION_NAME)
vector_store = ChromaVectorStore(chroma_collection=collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
VectorStoreIndex(nodes, storage_context=storage_context, show_progress=True)

Online Query

For each user question, the system:

Loads the persisted Chroma index.

Embeds the query using the cloud embedding model.

Retrieves the top‑k most similar chunks.

Formats each chunk with source metadata (file name and header path).

Constructs a prompt that instructs the LLM to answer solely from the retrieved references, includes the references list, and appends the user question.

Calls the cloud LLM via an OpenAI‑compatible chat API to generate the final answer.

def answer(index, question: str):
    retriever = index.as_retriever(similarity_top_k=TOP_K)
    nodes = retriever.retrieve(question)
    if not nodes:
        return "知识库中未找到相关内容。", ""
    context_parts = []
    for i, node in enumerate(nodes, start=1):
        source = format_source(node.node.metadata)
        context_parts.append(f"【{i}】来源:{source}
{node.node.text}")
    context = "

".join(context_parts)
    prompt = (
        "你是一个博客知识库助手。请仅根据下方「参考资料」回答用户问题。

"
        "要求:
"
        "1. 只使用参考资料中的信息,不要编造。
"
        "2. 如果参考资料中没有相关内容,直接回答「知识库中未找到相关内容」。
"
        "3. 引用信息时在句末标注 [序号],序号对应下方资料编号,例如 [1]、[2]。

"
        "参考资料:
" + context + "

用户问题:" + question + "

回答:"
    )
    answer_text = complete_answer(prompt).strip()
    # Build citation list
    sources_lines = []
    for i, node in enumerate(nodes, start=1):
        score = node.score if node.score is not None else 0.0
        sources_lines.append(f"  [{i}] {format_source(node.node.metadata)} (相似度 {score:.3f})")
    sources_text = "
".join(sources_lines)
    return answer_text, sources_text

Further Exploration

The author suggests that deeper control can be achieved by hosting local embedding and LLM models, eliminating any risk of sensitive data leakage.

All source code, configuration snippets, and deployment instructions are provided to enable reproducibility.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AIRAGdifyGitHub PagesllamaIndexChromadocmd
Java Baker
Written by

Java Baker

Java architect and Raspberry Pi enthusiast, dedicated to writing high-quality technical articles; the same name is used across major platforms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.