Skip to main content

🚀 EduChain

Python License Status Tests PyPI version

An educational Python framework inspired by LangChain — built from scratch to understand how modern LLM frameworks work internally.

EduChain recreates the core building blocks of LangChain by hand — including the parts most frameworks hide behind an import statement, like cosine similarity search, streaming source detection, and the agent reasoning loop. Instead of treating LLM frameworks as a black box, EduChain is about understanding the design patterns, abstractions, and architecture behind them well enough to build them yourself.

Note: EduChain is an educational project. It is not intended to replace LangChain or be feature-compatible with it.


✨ Features

Core Primitives

  • ✅ Runnable Abstraction (invoke() / stream() / ainvoke())
  • ✅ Prompt Templates
  • ✅ Chat Model Wrapper
  • ✅ Output Parsers (String, JSON)
  • ✅ RunnableSequence (with | operator, auto-flattening)
  • ✅ RunnableParallel
  • ✅ RunnablePassthrough
  • ✅ RunnableLambda

Memory

  • ✅ Chat History / Memory Module

Execution Models

  • ✅ Streaming (token-by-token, smart source/transformer detection)
  • ✅ Async Execution (ainvoke, true concurrency via asyncio.gather)
  • ✅ Callback System (pluggable hooks — no hardcoded logging)

Agentic Capabilities

  • ✅ Tool Calling (auto-generated schemas from Python type hints)
  • ✅ Vector Stores (in-memory, hand-written cosine similarity)
  • ✅ RAG (Retrieval-Augmented Generation)
  • ✅ Agents (multi-step tool-calling reasoning loop)

Engineering Fundamentals

  • ✅ Input Validation across every component
  • ✅ Modular Package Design
  • ✅ 36/36 tests passing (happy paths + validation + full-stack integration)

📂 Project Structure

EduChain/
│
├── educhain/
│   ├── core/
│   │   ├── runnable.py         → Runnable (base class)
│   │   ├── sequence.py         → RunnableSequence
│   │   ├── parallel.py         → RunnableParallel
│   │   ├── passthrough.py      → RunnablePassthrough
│   │   ├── lambda_runnable.py  → RunnableLambda
│   │   ├── history.py          → MessageHistory (raw store)
│   │   ├── callbacks.py        → CallbackHandler, PrintCallbackHandler
│   │   ├── tool.py             → Tool
│   │   ├── vectorstore.py      → InMemoryVectorStore
│   │   ├── rag.py              → RAGChain
│   │   └── agent.py            → Agent
│   ├── prompts/
│   │   └── prompt.py           → PromptTemplate
│   ├── models/
│   │   └── llm.py              → ChatModel
│   ├── output_parsers/
│   │   └── parser.py           → StringOutputParser, JsonOutputParser
│   └── memory/
│       └── chat_history.py     → ChatMessageHistory (chain wrapper)
│
├── test_all_features.py  → 36 tests, full coverage
├── demo_all_features.py  → core primitives, real usage
├── demo_async.py         → async execution + speed comparison
├── demo_callbacks.py     → callback system
├── demo_tools.py         → tool calling
├── demo_vectorstore.py   → semantic search
├── demo_rag.py           → retrieval-augmented generation
├── demo_agent.py         → full agentic reasoning loop
│
├── ROADMAP.md
├── README.md
├── requirements.txt
└── LICENSE

🏛 Architecture

                              Runnable
                                 │
    ┌───────────┬───────────┬───┴───────┬───────────┬──────────┐
    ▼           ▼           ▼           ▼           ▼          ▼
PromptTemplate ChatModel OutputParser Passthrough  Lambda     Agent
                    │                                           │
                    ▼                                           ▼
              (tools bound)                          ChatModel + Tools
                    │                                    + Callbacks
                    ▼                                           │
            RunnableSequence ◄──── RAGChain ◄──── InMemoryVectorStore
                    │
                    ▼
            RunnableParallel
                    │
                    ▼
            Memory & Chat History

Every component follows the same core interface:

invoke(input)      # synchronous
stream(input)      # chunked/streaming
ainvoke(input)     # async

Because every component behaves consistently, they compose into flexible pipelines — from a simple 3-step chain to a full agent that searches its own knowledge base.


⚡ Installation

pip install educhain-dks

Option 2: Clone the repository

git clone https://github.com/CodeWithDks/EduChain.git

Move into the project

cd EduChain

Create a virtual environment

python -m venv venv

Activate it

Windows

venv\Scripts\activate

Linux / macOS

source venv/bin/activate

Install dependencies

pip install -r requirements.txt

Create a .env file

OPENAI_API_KEY=your_api_key_here

🚀 Quick Start

Basic Chain

from educhain.prompts.prompt import PromptTemplate  # in short: from educhain.prompts import PromptTemplate
from educhain.models.llm import ChatModel           # in short: from educhain.model import ChatModel
from educhain.output_parsers.parser import StringOutputParser  # in short : from educhain.output_parser import StringOutputParser

prompt = PromptTemplate(
    template="Explain {topic} in simple words.",
    input_variables=["topic"]
)

model = ChatModel()
parser = StringOutputParser()

chain = prompt | model | parser

response = chain.invoke({"topic": "Artificial Intelligence"})
print(response)

Agent with Tools + RAG

from educhain.models.llm import ChatModel  # in short: from educhain.model import ChatModel
from educhain.core.tool import Tool
from educhain.core.agent import Agent

def get_weather(city: str) -> str:
    """Get the current weather for a specific named city."""
    return f"It's sunny in {city}"

weather_tool = Tool(get_weather)
model = ChatModel(tools=[weather_tool])
agent = Agent(model=model)

answer = agent.invoke("What's the weather like in Delhi?")
print(answer)

See demo_agent.py for a full example combining Tool Calling, RAG, and Callbacks together.


🔄 Execution Flow

Basic chain:

Dictionary → PromptTemplate → Formatted Prompt → ChatModel → AIMessage → OutputParser → Final Response

Agent loop:

Question → ChatModel (with tools) → tool call requested?
                                          │
                          yes ───────────┴──────── no
                           │                         │
                       run the tool             final answer
                           │
                   feed result back, repeat
                     (up to max_iterations)

🧩 Core Components

Runnable

The base abstraction of EduChain. Every component inherits from Runnable and implements invoke(), with optional stream() and ainvoke() overrides.

PromptTemplate

Formats prompts by replacing template variables with user input.

ChatModel

Wraps any LangChain-compatible chat model. Supports plain string prompts and full message-list conversations (needed for multi-turn tool calling). Optionally accepts tools=[...] to enable tool calling.

OutputParser

Transforms raw model outputs into clean Python objects — StringOutputParser and JsonOutputParser.

RunnableSequence

Executes multiple runnables sequentially via the | operator, with smart streaming support that correctly detects which step is the actual streaming source vs. a downstream transformer.

RunnableParallel

Executes multiple independent chains — concurrently via threads (invoke) or asyncio.gather (ainvoke).

Tool

Wraps a plain Python function as something an LLM can call — auto-generates the JSON schema from type hints and docstrings, no hand-written schema required.

InMemoryVectorStore

Stores text + embeddings, retrieves the most relevant chunks for a query using hand-written cosine similarity search.

RAGChain

Combines a vector store with an existing chain — retrieves relevant context, injects it into the prompt, generates a grounded answer.

Agent

Wraps a tool-bound ChatModel in a reasoning loop — decides which tool to call, executes it, feeds the result back, and repeats until it reaches a final answer (bounded by max_iterations as a safety limit).

CallbackHandler

Pluggable observability hooks (on_step_start, on_step_end, on_error, etc.) — swap in custom logging, timing, or monitoring logic without touching core chain code.


📚 Examples & Demos

demo_all_features.py  → core primitives working together
demo_async.py          → async chains + speed comparison
demo_callbacks.py       → built-in + custom callback handlers
demo_tools.py           → tool detection, execution, full round trip
demo_vectorstore.py     → semantic search across mixed topics
demo_rag.py             → retrieval-augmented generation, grounded answers
demo_agent.py           → full agentic loop, including RAG-as-a-tool

Run any demo directly:

python demo_agent.py

🧪 Tests

Run the full test suite (36 tests — happy paths, validation, and full-stack integration):

python test_all_features.py

🎯 Learning Objectives

EduChain was built to understand the engineering principles behind modern LLM frameworks — not just use them.

Topics covered include:

  • Object-Oriented Programming & Abstract Base Classes
  • Operator Overloading & Method Chaining
  • Software Architecture & Dependency Injection
  • Sequential and Parallel Pipelines (threads + asyncio)
  • Streaming (source vs. transformer detection)
  • Observer Pattern (Callback System)
  • Function Calling / Tool Use (JSON schema generation from type hints)
  • Vector Embeddings & Cosine Similarity (implemented by hand)
  • Retrieval-Augmented Generation
  • Agentic Reasoning Loops & Safety Limits (max_iterations)

🛣 Roadmap

✅ v1.0 — Complete

  • Runnable, PromptTemplate, ChatModel, OutputParser
  • RunnableSequence, RunnableParallel, RunnablePassthrough, RunnableLambda
  • Chat History / Memory
  • Streaming
  • Async Support
  • Callback System
  • Tool Calling
  • Vector Store
  • RAG Pipeline
  • Agents

💡 Future Directions (not committed)

  • Persistent storage for memory & vector store (swap in-memory for a real DB)
  • Pluggable vector store backends (FAISS/Chroma) behind the same interface
  • Multi-agent coordination
  • Streaming support inside the Agent loop
  • Batch processing (.batch())

See ROADMAP.md for full build history and design decisions.


📖 Documentation

Additional documentation is available in the docs/ directory and ROADMAP.md.


🤝 Contributing

Contributions, suggestions, and improvements are welcome. If you find a bug or have an idea for improving EduChain, feel free to open an issue or submit a pull request.


📄 License

This project is licensed under the MIT License.


🙏 Acknowledgements

EduChain is inspired by the architecture and design principles of LangChain. This project is an educational reimplementation created to better understand how modern LLM frameworks are designed. It is not affiliated with or endorsed by the LangChain project.


👨‍💻 Author

Deepak Kumar Singh GitHub

If you found this project helpful, consider giving it a ⭐ on GitHub.

Metadata

Release files for educhain-dks 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for educhain-dks 1.0.1
File Size Uploaded Provenance Actions
educhain_dks-1.0.1.tar.gz 32.3 kB Without provenance Details for educhain_dks-1.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for educhain-dks 1.0.1
File Interpreter ABI Platform Actions
educhain_dks-1.0.1-py3-none-any.whl Python 3 none any Details for educhain_dks-1.0.1-py3-none-any.whl

Total release size: 61.1 kB

Release files / educhain_dks-1.0.1.tar.gz

Download URL educhain_dks-1.0.1.tar.gz
Size 32.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d40ada4c6d63e4e2d0e470a3e3505dd39089752f986e80591f60a1b66f2df326
BLAKE2b-256 checksum
How to use checksums
5904120304009fdcd4b2359552c12b2c7a52ca7c8db477dd1fc380f459bbc06f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.13

Release files / educhain_dks-1.0.1-py3-none-any.whl

Download URL educhain_dks-1.0.1-py3-none-any.whl
Size 28.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8791f433714566ffcb1c39b7bff81cb091a3c550c9371ea831d4f4331d59873f
BLAKE2b-256 checksum
How to use checksums
d10802877d6f65f2cc55fa7bd00a2a5c79c13ab636c0b6acbd3c3208f2707e8d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.13

Security for educhain-dks 1.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page