Build Local Agentic AI: Multi-Agent Workflows with AutoGen, LangChain & Hugging Face
Why run agentic AI locally?
Agentic AI combines reasoning, planning, and execution across multiple collaborating agents. This tutorial demonstrates how to assemble a practical, fully local pipeline using LangChain, AutoGen concepts, and Hugging Face models — no paid APIs required. The examples show how to load models, compose LangChain prompt chains, implement light multi-agent workflows, simulate AutoGen-style orchestrations, and combine everything into a hybrid system.
Model setup and environment
Start by loading a local Hugging Face text2text pipeline (FLAN-T5 in this example) and wrapping it for use in LangChain and simple agents. This minimal setup is enough to experiment with chains, multi-step reasoning, and agent interactions.
import warnings
warnings.filterwarnings('ignore')
from typing import List, Dict
import autogen
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain_community.llms import HuggingFacePipeline
from transformers import pipeline
import json
print(" Loading models...\n")
pipe = pipeline(
"text2text-generation",
model="google/flan-t5-base",
max_length=200,
temperature=0.7
)
llm = HuggingFacePipeline(pipeline=pipe)
print("✓ Models loaded!\n")
This block configures a local FLAN-T5 model and a HuggingFacePipeline wrapper for LangChain. With models loaded, you can build prompt chains and agent loops without external calls.
LangChain basics and multi-step reasoning
LangChain makes it easy to define prompt templates and chain them to get structured, step-by-step outputs. The first demo shows a single-step chain for task decomposition and the second demo illustrates breaking a goal into steps and executing the first step.
def demo_langchain_basics():
print("="*70)
print("DEMO 1: LangChain - Intelligent Prompt Chains")
print("="*70 + "\n")
prompt = PromptTemplate(
input_variables=["task"],
template="Task: {task}\n\nProvide a detailed step-by-step solution:"
)
chain = LLMChain(llm=llm, prompt=prompt)
task = "Create a Python function to calculate fibonacci sequence"
print(f"Task: {task}\n")
result = chain.run(task=task)
print(f"LangChain Response:\n{result}\n")
print("✓ LangChain demo complete\n")
def demo_langchain_multi_step():
print("="*70)
print("DEMO 2: LangChain - Multi-Step Reasoning")
print("="*70 + "\n")
planner = PromptTemplate(
input_variables=["goal"],
template="Break down this goal into 3 steps: {goal}"
)
executor = PromptTemplate(
input_variables=["step"],
template="Explain how to execute this step: {step}"
)
plan_chain = LLMChain(llm=llm, prompt=planner)
exec_chain = LLMChain(llm=llm, prompt=executor)
goal = "Build a machine learning model"
print(f"Goal: {goal}\n")
plan = plan_chain.run(goal=goal)
print(f"Plan:\n{plan}\n")
print("Executing first step...")
execution = exec_chain.run(step="Collect and prepare data")
print(f"Execution:\n{execution}\n")
print("✓ Multi-step reasoning complete\n")
These examples highlight how chaining prompt templates can yield structured plans and concrete execution steps. Use them to prototype planners, explainers, and decomposers.
Building lightweight multi-agent systems
A multi-agent setup assigns roles to separate agent instances that exchange messages and build on each other’s outputs. The SimpleAgent below demonstrates a small, role-driven agent that uses the same local pipeline for responses and maintains simple memory.
class SimpleAgent:
def __init__(self, name: str, role: str, llm_pipeline):
self.name = name
self.role = role
self.pipe = llm_pipeline
self.memory = []
def process(self, message: str) -> str:
prompt = f"You are a {self.role}.\nUser: {message}\nYour response:"
response = self.pipe(prompt, max_length=150)[0]['generated_text']
self.memory.append({"user": message, "agent": response})
return response
def __repr__(self):
return f"Agent({self.name}, role={self.role})"
def demo_simple_agents():
print("="*70)
print("DEMO 3: Simple Multi-Agent System")
print("="*70 + "\n")
researcher = SimpleAgent("Researcher", "research specialist", pipe)
coder = SimpleAgent("Coder", "Python developer", pipe)
reviewer = SimpleAgent("Reviewer", "code reviewer", pipe)
print("Agents created:", researcher, coder, reviewer, "\n")
task = "Create a function to sort a list"
print(f"Task: {task}\n")
print(f"[{researcher.name}] Researching...")
research = researcher.process(f"What's the best approach to: {task}")
print(f"Research: {research[:100]}...\n")
print(f"[{coder.name}] Coding...")
code = coder.process(f"Write Python code to: {task}")
print(f"Code: {code[:100]}...\n")
print(f"[{reviewer.name}] Reviewing...")
review = reviewer.process(f"Review this approach: {code[:50]}")
print(f"Review: {review[:100]}...\n")
print("✓ Multi-agent workflow complete\n")
In this pattern, agents have distinct responsibilities — researching, producing code, and reviewing. Their interactions form a simple pipeline for collaborative problem solving.
Conceptual AutoGen configuration and simulation
AutoGen is a higher-level idea for coordinating multiple agents, often with specialized roles and feedback loops. The next example outlines a conceptual agent configuration and then simulates AutoGen-style behavior with a mock LLM so you can safely emulate multi-agent conversations.
def demo_autogen_conceptual():
print("="*70)
print("DEMO 4: AutoGen Concepts (Conceptual Demo)")
print("="*70 + "\n")
agent_config = {
"agents": [
{"name": "UserProxy", "type": "user_proxy", "role": "Coordinates tasks"},
{"name": "Assistant", "type": "assistant", "role": "Solves problems"},
{"name": "Executor", "type": "executor", "role": "Runs code"}
],
"workflow": [
"1. UserProxy receives task",
"2. Assistant generates solution",
"3. Executor tests solution",
"4. Feedback loop until complete"
]
}
print(json.dumps(agent_config, indent=2))
print("\n AutoGen Key Features:")
print(" • Automated agent chat conversations")
print(" • Code execution capabilities")
print(" • Human-in-the-loop support")
print(" • Multi-agent collaboration")
print(" • Tool/function calling\n")
print("✓ AutoGen concepts explained\n")
class MockLLM:
def __init__(self):
self.responses = {
"code": "def fibonacci(n):\n if n <= 1:\n return n\n return fibonacci(n-1) + fibonacci(n-2)",
"explain": "This is a recursive implementation of the Fibonacci sequence.",
"review": "The code is correct but could be optimized with memoization.",
"default": "I understand. Let me help with that task."
}
def generate(self, prompt: str) -> str:
prompt_lower = prompt.lower()
if "code" in prompt_lower or "function" in prompt_lower:
return self.responses["code"]
elif "explain" in prompt_lower:
return self.responses["explain"]
elif "review" in prompt_lower:
return self.responses["review"]
return self.responses["default"]
def demo_autogen_with_mock():
print("="*70)
print("DEMO 5: AutoGen with Custom LLM Backend")
print("="*70 + "\n")
mock_llm = MockLLM()
conversation = [
("User", "Create a fibonacci function"),
("CodeAgent", mock_llm.generate("write code for fibonacci")),
("ReviewAgent", mock_llm.generate("review this code")),
]
print("Simulated AutoGen Multi-Agent Conversation:\n")
for speaker, message in conversation:
print(f"[{speaker}]")
print(f"{message}\n")
print("✓ AutoGen simulation complete\n")
Using a mock LLM allows repeatable, predictable simulations of how agents might interact in a full AutoGen orchestration.
Hybrid: LangChain analysis + agents for planning and execution
Combining LangChain’s structured reasoning with role-based agents yields a hybrid system where each component plays a clear part: LangChain analyzes the problem and produces steps, an agent crafts a plan, and another agent simulates execution.
def demo_hybrid_system():
print("="*70)
print("DEMO 6: Hybrid LangChain + Multi-Agent System")
print("="*70 + "\n")
reasoning_prompt = PromptTemplate(
input_variables=["problem"],
template="Analyze this problem: {problem}\nWhat are the key steps?"
)
reasoning_chain = LLMChain(llm=llm, prompt=reasoning_prompt)
planner = SimpleAgent("Planner", "strategic planner", pipe)
executor = SimpleAgent("Executor", "task executor", pipe)
problem = "Optimize a slow database query"
print(f"Problem: {problem}\n")
print("[LangChain] Analyzing problem...")
analysis = reasoning_chain.run(problem=problem)
print(f"Analysis: {analysis[:120]}...\n")
print(f"[{planner.name}] Creating plan...")
plan = planner.process(f"Plan how to: {problem}")
print(f"Plan: {plan[:120]}...\n")
print(f"[{executor.name}] Executing...")
result = executor.process(f"Execute: Add database indexes")
print(f"Result: {result[:120]}...\n")
print("✓ Hybrid system complete\n")
This hybrid flow shows how to split responsibilities between reasoning (LangChain) and action (agents), improving modularity and traceability of agentic behavior.
Running the full tutorial
The following main block ties all demos together, running each component sequentially so you can observe them working end-to-end.
if __name__ == "__main__":
print("="*70)
print(" ADVANCED AGENTIC AI TUTORIAL")
print("AutoGen + LangChain + HuggingFace")
print("="*70 + "\n")
demo_langchain_basics()
demo_langchain_multi_step()
demo_simple_agents()
demo_autogen_conceptual()
demo_autogen_with_mock()
demo_hybrid_system()
print("="*70)
print(" TUTORIAL COMPLETE!")
print("="*70)
print("\n What You Learned:")
print(" ✓ LangChain prompt engineering and chains")
print(" ✓ Multi-step reasoning with LangChain")
print(" ✓ Building custom multi-agent systems")
print(" ✓ AutoGen architecture and concepts")
print(" ✓ Combining LangChain + agents")
print(" ✓ Using HuggingFace models (no API needed!)")
print("\n Key Takeaway:")
print(" You can build powerful agentic AI systems without expensive APIs!")
print(" Combine LangChain's chains with multi-agent architectures for")
print(" intelligent, autonomous AI systems.")
print("="*70 + "\n")
This codebase and structure provide a reproducible foundation for experimenting with autonomous agent workflows locally. Extend agents, add tool integrations, include execution environments, or swap models to explore different agent behaviors and capabilities.