Skip to main content
Glama
hailampy123

solid-knowledge-ai

by hailampy123

Solid Knowledge AI

A multi-source document knowledge assistant driven by a self-reflective LangGraph agent. It ingests PDF + Markdown + web pages into one vector store, then answers questions through an agent that grades its own retrieval and verifies its own answer for grounding — retrying with a rewritten query when either check fails, and refusing to fabricate when it can't ground an answer. Traced with Langfuse, quality-tested with DeepEval, and exposed over MCP.

Built to showcase agentic development: LangGraph · LiteLLM · ChromaDB · MCP · Langfuse · DeepEval.

Why this is not "just RAG"

The agent is a corrective / self-reflective RAG loop, not a linear retrieve → generate chain:

question
   │
   ▼
 route ──chitchat/out_of_scope──▶ generate ──▶ END
   │ kb
   ▼
retrieve ──▶ grade_docs ──irrelevant (rewrite query, retry)──▶ retrieve
                 │ relevant
                 ▼
             generate ──▶ self_check ──ungrounded (retry)──▶ retrieve
                              │ grounded / budget spent
                              ▼
                     answer + citations  (or an honest "I don't know")
  • route — skips retrieval on small talk / out-of-scope questions.

  • grade_docs — an LLM relevance gate; on failure it rewrites the query and retries.

  • self_check — verifies the drafted answer is entailed by the retrieved context; if not, it retries or hedges instead of hallucinating.

  • A shared retry budget (max_retries, default 2) bounds both loops.

  • Memory — a SQLite checkpointer keeps multi-turn conversation state per thread_id.

Related MCP server: PDF MCP Server

Quickstart

# 1. Install (Python 3.11+, uv)
uv sync

# 2. Configure — only ANTHROPIC_API_KEY is required
cp .env.example .env      # then edit .env

# 3. Ingest the sample corpus (2 Markdown + 1 PDF + 1 Wikipedia article)
uv run skai ingest        # -> builds ./.chroma  (local MiniLM embeddings, no API)

# 4. Ask (defaults to Haiku 4.5; switch per-call with --model)
uv run skai ask "What do orcas eat?"
uv run skai ask "How do orcas communicate?" --source md
uv run skai ask "Summarize orca threats" --model sonnet   # haiku | sonnet (Opus blocked)

# 5. Multi-turn chat (remembers the conversation)
uv run skai chat

# 6. Web UI (chat + feedback + live data ingestion)
uv run skai ui        # http://localhost:7860

# 7. Serve over MCP (stdio) for Claude Desktop / an IDE
uv run skai mcp

Web UI

skai ui launches a Gradio app with the features a live demo needs:

  • Chat with per-session memory; every answer shows its sources, route, and model.

  • Feedback after every response — 👍/👎 + an optional comment, stored to SQLite (.skai/feedback.sqlite) and pushed as a Langfuse score on that turn's trace when tracing is on. That's the closed loop: real usage becomes an eval signal.

  • Example prompts to guide the first interaction.

  • Grow the knowledge base live — upload a .md/.txt/.pdf or paste a URL and it's ingested into Chroma on the spot, so the demo isn't limited to the seed corpus.

  • Model (haiku/sonnet) and source filter (all/pdf/md/web) selectors.

Feedback is exportable to a JSONL eval seed via skai.feedback.export_jsonl.

Commands

Command

What it does

skai ingest [--path data/docs --urls data/urls.txt --reset]

Load → chunk → embed → persist to Chroma

skai ask "..." [--source pdf|md|web] [--thread-id X]

One-shot question with citations

skai chat

Interactive multi-turn chat with memory

skai ui [--port 7860 --share]

Gradio web UI: chat, feedback, live ingestion

skai mcp

Run the MCP server exposing search_kb and ask

skai eval

Run the DeepEval quality suite (needs --group eval + key)

MCP client config

The server exposes two tools — search_kb(query, source_type?) (raw retrieval) and ask(question) (full agent). Point an MCP client at it:

{
  "mcpServers": {
    "solid-knowledge-ai": {
      "command": "uv",
      "args": ["run", "skai", "mcp"],
      "cwd": "/absolute/path/to/solid-knowledge-ai"
    }
  }
}

Model selection

Default Haiku 4.5 (fast, cheap — good for a Q&A router+grader+generator loop). Switch per call with --model, or globally via SKAI_MODEL in .env:

Value

Resolves to

haiku (default)

anthropic/claude-haiku-4-5

sonnet

anthropic/claude-sonnet-4-5

any LiteLLM id

passed through (e.g. openai/gpt-4o-mini)

Opus is intentionally blocked (resolve_model raises), so the assistant can't be pointed at the most expensive tier by accident.

Observability

Set LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY (and optionally LANGFUSE_HOST) in .env. Every graph run then produces one trace with a span per node and per LLM call. Without keys, tracing is a clean no-op — nothing else changes.

Quality evaluation (DeepEval)

uv sync --group eval
export ANTHROPIC_API_KEY=...
uv run skai ingest
uv run --group eval pytest evals -v      # or: skai eval

The judge is Claude via LiteLLM, so no OpenAI key is needed. Metrics: faithfulness, answer relevancy, contextual relevancy — plus a cheap keyword gate.

Tests

uv run pytest        # 39 tests, fully offline: no network, no API keys

The LLM is dependency-injected, so the whole graph runs in tests against a deterministic stub, and Chroma uses a deterministic in-process embedding function.

How it's put together

src/skai/
  config.py            settings (.env)              agent/llm.py     ChatLiteLLM -> Claude
  models.py            Document/Chunk/AgentState    agent/nodes.py   route/retrieve/grade/generate/self_check
  ingest/loaders.py    pdf | md | web  -> Document  agent/prompts.py node prompts
  ingest/chunk.py      source-aware splitting       agent/graph.py   StateGraph + SQLite memory
  ingest/store.py      Chroma add/query             observability.py Langfuse handler (or no-op)
  cli.py               ingest|ask|chat|mcp|eval     mcp_server.py    search_kb / ask as MCP tools
evals/                 DeepEval suite               tests/           offline unit + graph tests

Agent graph & component diagrams (Mermaid): see docs/ARCHITECTURE.md. Design rationale and tech trade-offs: see docs/DECISIONS.md. Where it goes next (capability & use cases): see docs/CAPABILITY-ROADMAP.md. Running it on Gemini Enterprise CX / Google Cloud: see docs/GEMINI-ENTERPRISE-PORT.md

Status

Verified: uv run skai ingest loads all three source types (2 md + 1 pdf + 1 web → 170 chunks) and real semantic retrieval returns relevant passages. 39 offline tests pass. ask/chat/eval require an ANTHROPIC_API_KEY

Available Tools

2 tools
askB

Ask the self-reflective knowledge agent. Returns a grounded, cited answer.

ParametersJSON Schema
NameRequiredDescriptionDefault
questionYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry behavior disclosure; it does say outputs are grounded and cited, a meaningful trait. However, it does not mention limitations, confidence, citation format, or whether the agent can refuse/ask follow-ups, leaving the behavioral profile thin.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, with the core instruction and return behavior front-loaded. No filler or redundant restatement of the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter tool with an output schema, the description covers the key behavior and return characteristic. It is mostly complete, though the lack of sibling differentiation and parameter detail keeps it from being fully self-sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has a single required `question` string with no field description, and the description does not elaborate on expected question format, length, or scope. The parameter name is self-explanatory, but the description adds no semantic detail to compensate for 0% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action ('Ask') on a distinct resource ('self-reflective knowledge agent') and its output ('grounded, cited answer'). It does not explicitly compare itself to search_kb, but the resource and output type give enough differentiation for a general sense.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to ask versus using search_kb, nor any exclusions or conditions. The name and description imply Q&A usage, but the agent is not told when to choose this tool over the sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_kbC

Semantic search over the ingested documents. Optional source_type: pdf|md|web.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
source_typeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the full burden of disclosing behavior. It reveals that the tool searches over ingested documents and accepts an optional source_type, but it does not disclose result limits, relevance behavior, authentication needs, or any side effects. For a read/search tool this is a notable but not severe gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single tight sentence followed by a compact optional-parameter note. It is front-loaded with the core action and resource, and every word adds information. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter search tool, the description covers the essential invocation surface, and an output schema likely documents return values. However, it omits any comparison with 'ask' and does not explain result behavior or limitations, leaving the agent to infer when this tool is appropriate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does add meaning to source_type by enumerating allowed values ('pdf|md|web'), but it leaves the main 'query' parameter semantically undefined beyond the schema's bare type declaration. The compensation is only partial.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Semantic search') on a clear resource ('ingested documents') and lists the optional source_type filter. It does not explicitly name the sibling tool 'ask' as the alternative, so some differentiation is left to inference, but the operation is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to prefer search_kb over the sibling tool 'ask', nor any exclusions or prerequisites. Usage context is only implied by the phrase 'semantic search', which is not enough to route an agent reliably.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 2 tool updatesv0.1.0
    • First observedask
    • First observedsearch_kb

TDQS

B3.2/5.0
Disambiguation4/5

The two tools are distinct in purpose: search_kb returns semantic search results over sources, while ask provides a grounded, cited answer through an agent. There is some overlap in that both retrieve information from the same knowledge base, but the descriptions clearly differentiate a low-level search from a high-level Q&A interaction, making misselection unlikely.

Naming Consistency4/5

Both tool names use lowercase snake_case and are verb-based. 'search_kb' follows a verb_noun pattern while 'ask' is a bare verb, creating a minor inconsistency, but the pattern is still simple and predictable given the small set.

Tool Count3/5

With only two tools, the server feels thin but not unreasonable. Search and ask cover the core knowledge-access functions, though additional tools like listing sources or managing documents might be expected in a fuller knowledge-management server.

Completeness4/5

The tool surface covers the core domain of querying an ingested knowledge base: search_kb for retrieval and ask for synthesized answers. Minor gaps exist, such as no way to enumerate available sources or inspect document metadata, but these are not critical for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hailampy123/solid-knowledge-ai'

If you have feedback or need assistance with the MCP directory API, please join our Discord server