🚀 EduChain
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 viaasyncio.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
Option 1: Via PyPI (Recommended)
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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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.