Multi-tool LangGraph agent — "Personal Assistant Pro"
A single agent with calendar, email, search, and RAG tools, plus tracing and human-in-the-loop approvals.
After Phase 3. This is the project that proves you can ship a single intelligent agent — not just a chain. It is the canonical agentic AI portfolio piece.
What you ship
A LangGraph agent with 6+ real tools, persistent memory across sessions, human-in-the-loop approvals for sensitive actions, observability, and a Streamlit UI. The agent feels like yours: it remembers preferences, runs over multi-day conversations, and is robust to flaky downstreams.
Tools (pick or design 6)
- Web search (Tavily / Brave).
- Calendar (Google Calendar API or a CSV stub).
- Email drafter (creates drafts in Gmail; never sends without approval).
- Notes (read/write your Obsidian vault or a local SQLite).
- Calculator / Python sandbox (E2B or
restrictedpython). - Currency convert (Frankfurter API).
- Stock price (yfinance).
- Personal RAG over your notes (Project 1 reused).
Stack
- LangGraph 1.x with
StateGraph, conditional edges,interrupt(). SqliteSaver(orPostgresSaver) for persistence.- Mem0 for long-term user memory.
- LangSmith tracing.
- Tenacity retries + Purgatory circuit breaker.
- Streamlit UI + FastAPI service.
Architecture (mermaid)
mermaid
flowchart TD
USR[User] -->|chat| UI[Streamlit]
UI --> API[FastAPI /ask]
API --> CKPT[(SqliteSaver)]
API --> MEM[(Mem0 user memories)]
API --> G[LangGraph]
G --> ROUTER{Need tools?}
ROUTER -- yes --> TOOLS[Parallel tool calls]
TOOLS --> SAFE[Tool gate: confirm + RBAC + rate-limit]
SAFE --> RES[Tool results]
RES --> G
ROUTER -- no --> ANS[Final answer]
G --> HIL{High-impact action?}
HIL -- yes --> INT[interrupt() for approval]
INT --> UIStep-by-step
Day 1 — Skeleton
- Define
State(messages, user_id, step_count, pending_approvals). - Build a single-tool ReAct agent with
create_agentto verify the loop. - Add SqliteSaver and confirm 2-turn memory works.
Day 2 — Tools
- Define each tool with Pydantic args and clean docstrings.
- Add a
tool_dispatchernode with try/except, retry, and per-tool latency logging. - Add a loop guard (no same tool+args twice in a row).
Day 3 — Memory layer
- Hook Mem0 in: search at the start of each turn, store at the end.
- Sidebar in Streamlit shows current memories with delete buttons.
- Add a
forget_user(user_id)admin endpoint.
Day 4 — Human approvals
- Convert any side-effecting tool (
send_email,book_meeting) to a 2-step pattern:propose_*andconfirm_*. - Use
interrupt()between propose and confirm; the UI shows the proposal as a card with Approve/Reject buttons.
Day 5 — Observability + reliability
- Add
LANGSMITH_TRACING=true. Confirm the graph + tools show up. - Tenacity retry on every external HTTP call.
- Circuit breaker for the calendar API.
- structlog JSON logs with
user_id,request_id.
Day 6 — Evals
- 50 trajectory tests (Lesson 5.1) covering happy + edge + adversarial cases.
- DeepEval
ToolCorrectnessMetric+TaskCompletionMetric. - Hook into a GitHub Action; PR fails if pass rate drops.
Day 7 — Polish
- Write the post: video demo, screenshots, mermaid, eval matrix, cost / latency tables.
- Make a
make demothat spins everything up locally.
Acceptance checklist
- At least 6 tools with Pydantic schemas and unit tests.
- Persistence across process restarts (kill server, start, conversation continues).
- HIL with
interrupt()working end-to-end in the UI. - Streamlit memory sidebar with edit/delete.
- LangSmith trace link in README.
- DeepEval CI gate; PR with bad change is auto-rejected.
- README explains why you chose LangGraph over a manual loop.
What hiring managers love
- A graph diagram (mermaid) — most candidates do not draw it.
- A real HIL flow (not a TODO).
- Trajectory eval, not just final-answer.
- A short "common failure modes I saw and fixed" section.
This project, done well, makes you a strong "Agent Engineer" candidate at most companies. Ship it.