LangChain & LangGraph
Reference architectures
For a personal assistant that can both schedule meetings and send emails, I like the supervisor + subagents pattern. Instead of one giant agent with dozens of tools and prompts, you build a small set of specialists (calendar, email, knowledge lookup, etc.) and a single supervisor that decides which specialist to call.
At a high level there are three layers:
- Raw tools — low-level actions like creating calendar events or sending emails.
- Subagents — focused agents that speak natural language but only know about a narrow toolset (for example calendar or email).
- Supervisor — a top-level agent that routes user requests to the right subagent and stitches the results together.
This separation keeps prompts simpler, lets you evolve calendar and email logic independently, and gives you a clear place to insert governance features like human-in-the-loop review or policy checks.
Example projects
Below is a simplified sketch of a multi-agent personal assistant using LangChain and LangGraph. One subagent manages calendar operations, another manages email, and a supervisor coordinates them.
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from langchain.tools import tool
"""Low-level tools (in real projects these would hit real APIs)."""
@tool
def create_calendar_event(title: str, when: str, attendees: list[str]) -> str:
"""Create a calendar event. `when` is an ISO-ish datetime string."""
return f"[calendar] '{title}' at {when} for {', '.join(attendees) or 'nobody yet'}"
@tool
def send_email(to: list[str], subject: str, body: str) -> str:
"""Send an email. Returns a short confirmation string."""
return f"[email] to {', '.join(to)} with subject '{subject}'"
"""Subagents: focused assistants that only know about one domain."""
CALENDAR_PROMPT = (
"You are a calendar assistant. "
"Turn natural language scheduling requests into concrete events. "
"Parse dates/times, pick a reasonable slot, and call create_calendar_event."
)
EMAIL_PROMPT = (
"You are an email assistant. "
"Given a request, draft a concise, professional email and call send_email."
)
model = init_chat_model("gpt-4.1")
calendar_agent = create_agent(
model,
tools=[create_calendar_event],
system_prompt=CALENDAR_PROMPT,
)
email_agent = create_agent(
model,
tools=[send_email],
system_prompt=EMAIL_PROMPT,
)
"""Wrap subagents as high-level tools for the supervisor."""
@tool
def schedule_event(request: str) -> str:
"""Use natural language to schedule a meeting or reminder."""
result = calendar_agent.invoke({
"messages": [HumanMessage(request)],
})
return result["messages"][-1].text
@tool
def manage_email(request: str) -> str:
"""Use natural language to send or draft an email."""
result = email_agent.invoke({
"messages": [HumanMessage(request)],
})
return result["messages"][-1].text
SUPERVISOR_PROMPT = (
"You are a personal assistant. "
"You can schedule events and send emails via tools. "
"Work out which tool (or tools) a request needs and summarise what you did."
)
supervisor = create_agent(
model,
tools=[schedule_event, manage_email],
system_prompt=SUPERVISOR_PROMPT,
)
query = (
"Next Tuesday, set up a 30 minute sync with the design team at 2pm "
"and email them a reminder with the meeting details."
)
result = supervisor.invoke({"messages": [HumanMessage(query)]})
for msg in result["messages"]:
msg.pretty_print()
For production use you would replace the stubbed tools with real calendar and email APIs, add human-in-the-loop review for sensitive actions and plug the system into chat, ticketing or CRM front-ends. The architectural idea stays the same: narrow subagents wrapped as tools, plus a supervisor that routes and summarises.
Lessons learned
A few practices that I find especially useful when building personal assistants with a supervisor pattern:
- Draw clear domain boundaries. Create subagents for coherent domains (calendar, email, CRM) rather than every individual tool. Each subagent should have a small prompt and a small toolset.
-
Write good tool descriptions. The supervisor
only sees high-level tools like
schedule_eventormanage_email. Clear docstrings and examples help it choose the right one. - Instrument heavily. Use LangSmith (or your preferred tracing stack) to record prompts, tool calls, state transitions and latency. Multi-step routing can otherwise feel opaque.
- Design for failure paths. Decide how the system behaves when subagents cannot parse dates, infer recipients or when tools fail. Provide clear fallbacks and escalation options.
- Start narrow, then generalise. It is usually better to ship one or two domains (for example calendar and email) and expand to more capabilities once the pattern is stable.