Skip to main content

A mini LangChain clone, built from scratch to understand how modern LLM frameworks work internally.

Project description

๐Ÿš€ EduChain

Python License Status Tests

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

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
from educhain.models.llm import ChatModel
from educhain.output_parsers.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
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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

educhain_dks-1.0.0.tar.gz (31.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

educhain_dks-1.0.0-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

Details for the file educhain_dks-1.0.0.tar.gz.

File metadata

  • Download URL: educhain_dks-1.0.0.tar.gz
  • Upload date:
  • Size: 31.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for educhain_dks-1.0.0.tar.gz
Algorithm Hash digest
SHA256 1434ce301f60f4476487056772ca57c894bf59bdb1c44899712a1d8f342ba863
MD5 59d44afe27efcc23fd5f7066b4b3f919
BLAKE2b-256 6b6a6ed6e7749e8c1e0f732d187c95b910c629cbe9e3484151b769fc9b5ff4f8

See more details on using hashes here.

File details

Details for the file educhain_dks-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: educhain_dks-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 28.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for educhain_dks-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d00c0a3f97c04ba23cdb0498e9c3828dbc41a824c77bb6e31e81287b34f96dae
MD5 2d6ee7ef7d37cd8377615fcbca298004
BLAKE2b-256 5e9d04218fc7f13b0c06eff10597ee53e771161a394a70b0c8a3b01c3f9b2278

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page