A
frameto help you reason through the assignment — concepts, diagrams, and the API map. It deliberately doesnotcontain the answers or filled-in activity code. Instead it gives you thequestions to ask yourselfand themethodto get there. The work — and the learning — is in packaging the agent,inspecting a Studio/LangSmith trace, shipping it, and writing your own conclusions.Source repo:
09_Agent_Servers/
(a packaged LangGraph agent + a Next.jsfrontend/
).No notebook— Q1/Q2 are answered inREADME.md
. Corpus:data/cat_health_guidelines.pdf
(a feline-health PDF the RAG tool indexes in-memory; benign).
| You want to… | Reach for | One-liner |
|---|---|---|
| Tell LangGraph what graphs exist | langgraph.json graphs |
|
"simple_agent": "app.graphs.simple_agent:graph" (id → module:attribute ) |
||
| Export a runnable graph | a module-level graph |
|
graph = create_agent(model=..., tools=..., system_prompt=...) |
||
| Run the agent API locally | langgraph dev |
|
serves http://localhost:2024 + opens LangGraph Studio |
||
| Self-host a prod container | langgraph up |
|
| local Docker; you own scaling/uptime/auth | ||
| Deploy to LangSmith cloud | langgraph deploy |
|
| managed build+host (needs LangSmith Plus) → Deployment URL | ||
| Talk to the agent in Python | langgraph_sdk.get_client |
|
client.runs.stream(None, "agent", input={...}, stream_mode="updates") |
||
| Stream the agent into a UI | @langchain/react useStream |
|
useStream({ apiUrl: "/api", assistantId: "simple_agent" }) |
||
| Hide the API key from the browser | langgraph-nextjs-api-passthrough |
|
initApiPassthrough({ apiUrl, apiKey, runtime: "edge" }) in route.ts |
||
| Mark a var public in Next.js | NEXT_PUBLIC_ prefix |
|
only NEXT_PUBLIC_* reaches the browser; everything else is server-only |
||
| Deploy the UI | vercel / vercel --prod |
|
set LANGGRAPH_API_URL , LANGSMITH_API_KEY , NEXT_PUBLIC_API_URL |
||
| See what the agent actually did | LangSmith traces / Studio | every run is traced; Studio steps through nodes + tool calls |
Anchor: LangSmith hosts the agent as an API; Vercel hosts the UI and the
server-side proxy that injects the secret — the browser only ever talks to
same-origin /api/*
.
flowchart LR
User[User in browser] --> Vercel[Next.js UI on Vercel]
Vercel -->|"/api/* passthrough (injects key server-side)"| LS[LangSmith Agent API]
LS --> Agent[Your LangGraph graph]
Agent --> Tools[Tavily + Arxiv + RAG tool]
LS --> Traces[LangSmith tracing]
subgraph local[Local dev]
Dev["langgraph dev :2024"] --> Studio[LangGraph Studio]
end
ASCII fallback:
browser ─► Vercel UI ─► /api proxy (adds LANGSMITH_API_KEY server-side) ─► LangSmith Agent API ─► graph ─► tools
└─► LangSmith traces
local: langgraph dev :2024 ─► LangGraph Studio (debug/step/fork)
Why this shape? A deployed agent is a stateful API (threads / runs / assistants + streaming), not a website. The two deployment targets map to two concerns: LangSmith runs + observes the agent; Vercel serves the UI and keeps the secret on the trusted server tier. The same compiled graph runs in Studio (debug) and in production (hosted) — only the environment differs.
uv sync # agent deps (Python 3.13)
cp .env.example .env # fill OPENAI_API_KEY, TAVILY_API_KEY, LANGSMITH_API_KEY
cd frontend && npm install # the frontend ships complete — no create-next-app needed
| Component | Role |
|---|---|
app/models.py |
|
model factory get_chat_model() (default gpt-5.4-mini , temperature=0 ) |
|
app/tools.py |
|
tool belt: TavilySearch , ArxivQueryRun , retrieve_information (RAG) |
|
app/rag.py |
|
loads data/*.pdf → split 750/0 → text-embedding-3-small → in-memory Qdrant |
|
app/graphs/simple_agent.py |
|
create_agent(...) → exports compiled graph |
|
langgraph.json |
|
manifest: graphs + assistants the server exposes |
|
frontend/app/api/[...path]/route.ts |
|
| secure passthrough — injects the key server-side | |
frontend/components/chat.tsx |
|
useStream chat UI pointed at /api |
A notebook agent becomes a server by exporting a compiled graph and registering it.
langgraph.json
maps a graph_id
to "module:attribute"
and
declares named assistants
. dependencies: ["."]
installs the local package;
env: ".env"
loads keys. Docs: https://docs.langchain.com/langgraph-platform/
"graphs": { "simple_agent": "app.graphs.simple_agent:graph" }
langgraph dev
serves the Agent Server API at :2024
with hot reload and opens Studio. Studio = debugging: visualize topology, step through runs, inspect tool calls, fork threads, switch assistants. Not a production UI. Docs: https://docs.langchain.com/langgraph-platform/langgraph-studio
The production integration path. A passing local smoke test proves the manifest, graph import, and streaming all work — the README gate before deploying.
from langgraph_sdk import get_client
client = get_client(url="http://localhost:2024")
for chunk in client.runs.stream(None, "agent", input={"messages": [...]}, stream_mode="updates"):
...
langgraph deploy
= managed LangSmith cloud build+host (needs Plus) → a
https://<...>.us.langgraph.app
Deployment URL + optional auto-update-on-push.
langgraph up
= self-hosted Docker container. Either way you get the same API
surface (threads/runs/assistants) plus tracing. Docs:
https://docs.langchain.com/langsmith/deployments.
Docker/self-host instructions: langgraph up
(Docker required, production-like local) — https://docs.langchain.com/langsmith/local-dev-testing#langgraph-up; standalone Agent Servers via Docker / Docker Compose / Kubernetes — https://docs.langchain.com/langsmith/deploy-standalone-server.
Cloud deploy (langgraph deploy
or GitHub→UI) requires Plus — $39/seat/mo 1.
Free without Plus: everything local (
langgraph dev
- Studio + SDK, all of Part 1),
tracing (5k traces/mo on the Developer plan), and self-hosting via
langgraph up
(Docker). Check your plan: LangSmith →
Settings → Billing and Usage(
smith.langchain.com/settings/payments
) — a personalorg is
Developer(free, no cloud deploy); a
team/sharedorg is
Plus. An
*"Upgrade to Plus"*banner means you're not on it.
Upgrade is self-serve there (add a card);
Enterprise is contact-sales. Plus includes
1 free Dev deployment, unlimited runs— enough for this assignment; beyond it, ~$0.005/run plus uptime (⚠️ a Production deployment left running accrues cost).
No-Plus path to the deliverable: self-host with
langgraph up
, or record the Loom against the local Studio demo (the README accepts "Studio debugging" as one of its two demo options). Cost table:
.
2| Plan | Price | Free traces/mo | Cloud deploy? | |---|---|---|---| | Developer | $0/seat, 1 seat | 5,000 | ❌ | | Plus | $39/seat/mo | 10,000 | ✅ 1 free Dev deployment | | Enterprise | custom | custom | ✅ + self-hosted/hybrid |
create_agent
wires a ReAct-style agent: the model decides when to call a tool,
the tool runs, control returns until the model gives a final answer. Tools: Tavily
(web), Arxiv (papers), retrieve_information
(RAG over the cat-health PDF).
A "use client"
component subscribes to the agent's event stream and renders
messages as they arrive. Point it at the same-origin /api
proxy, not the LangSmith URL directly. Docs: https://www.npmjs.com/package/@langchain/react
const { messages, submit, is } = useStream({ apiUrl: "/api", assistantId: "simple_agent" });
Anything in client code is readable by the user. The passthrough route runs
server-side and injects LANGSMITH_API_KEY
into the upstream request; the
browser only sees /api/*
. Only NEXT_PUBLIC_*
vars are public. Docs: https://www.npmjs.com/package/langgraph-nextjs-api-passthrough
export const { GET, POST, ... } = initApiPassthrough({
apiUrl: process.env.LANGGRAPH_API_URL, apiKey: process.env.LANGSMITH_API_KEY, runtime: "edge" });
Set Root Directory to frontend
, add LANGGRAPH_API_URL
LANGSMITH_API_KEY
(server-only) + NEXT_PUBLIC_API_URL
, then vercel --prod
. Verify end-to-end: the live site streams, tool calls fire, traces appear in LangSmith. Docs: https://vercel.com/docs/frameworks/nextjs
Q1 — Why does LangSmith deploy your agent as an API backend only, and why still a separate Vercel frontend?
Method to get there — ask yourself:
- When you hit your deployed agent, what comes back — HTML you could render in a browser, or JSON/streamed events? What does that tell you about whether LangSmith can beyour website? - List what the agent API exposes (threads? runs? assistants?). Is any of that a user interface?
- If you skipped Vercel and pointed the browser directly at the LangSmith URL, what would the user need in the request — and what does §7 say about putting that in the browser?
- Frame your answer as "two concerns, two hosts." Name each host's job in one line.
Method to get there — ask yourself:
- Open devtools on any site → Network + Sources. What can you read? Could a secret compiled into client JS stay hidden?
- In Next.js, which env vars reach the browser? What does the
NEXT_PUBLIC_
prefix do, and why areLANGGRAPH_API_URL
/LANGSMITH_API_KEY
deliberatelynotprefixed whileNEXT_PUBLIC_API_URL
is? - Trace one request: browser →
/api/*
→ ? Where doesinitApiPassthrough
add the key — on the user's machine or on Vercel's server? - What could someone do with your key if they lifted it from the bundle? Let that consequence anchor your "why."
Deliverable: a new graph that, after the agent answers, has a judge model
decide whether the response was helpful and loops back for another attempt if not —
with a safe loop limit — registered in langgraph.json
, deployed, with traces compared for a passing vs failing query. Method to get there — ask yourself:
- The provided agent uses
create_agent
. Can you insert a step that runsafterthe final answer with it? If not, what lower-level construct lets you own the nodes and edges (and a cycle)? - What nodes do you need — who answers, who runs tools, who judges? Draw the edges: when does the judge send control backto the agent vs to the end? - How will the judge "decide"? What does it compare (the answer against…?), and how do you keep its output easy to branch on? What would happen if the judge kept saying "not helpful"? Design the loop limitfirst— what will you count, and where do you force the end?- In Studio/LangSmith, inspect both runs: does the passing query end in one pass? Does the failing one show the retry edge firing? Where do you seethe judge call? - Reflect (the README asks): is the loop's logicany different in Studio vs production — or is it the same graph in a different environment?
Deliverable: describe (optionally implement) how to add authentication so each user only sees their own threads. Method to get there — ask yourself:
- Hiding the chat page behind a login in React — does that actually stop someone from reading anotheruser's threads through the API? Where must the real check live? - What would the server need to know on each request to scope threads to one user, and what could you stamp on a thread when it's created so reads can be filtered?
- Where should the user's token be attached — the same place §7 puts the API key, or the browser? Why?
- Look at the README's
lsd-custom-route-react-ui
reference for the pattern.
Grounded against the LangChain docs and the LangChain pricing page (verify — plans and prices change; figures current ~mid-2026).
LangSmith Plus / deployment / cost (§4½):
- Billing setup, plan check, and upgrade-to-Plus steps —
https://docs.langchain.com/langsmith/billing - Deployment environments (Cloud vs standalone vs self-hosted; plan requirements) —
https://docs.langchain.com/langsmith/deployment - Local development & testing (
langgraph dev
vslanggraph up
) —https://docs.langchain.com/langsmith/local-dev-testing
Docker / self-host deployment ( langgraph up, standalone container):
- Self-host standalone Agent Servers —
Docker, Docker Compose, Kubernetes—https://docs.langchain.com/langsmith/deploy-standalone-server
langgraph up
(Docker required; production-like local: API + PostgreSQL + Redis on :8123) —https://docs.langchain.com/langsmith/local-dev-testing#langgraph-up- LangGraph CLI
up
/build
/dockerfile
commands —https://docs.langchain.com/langsmith/cli - Self-hosted deployment topologies (standalone vs hybrid vs full platform) — https://docs.langchain.com/langsmith/deploy-to-self-hosted-overview
Packaging, server, SDK, frontend:
- LangGraph CLI reference (
dev
/build
/deploy
/up
) —https://docs.langchain.com/langsmith/cli - Application structure (
langgraph.json
) —https://docs.langchain.com/langsmith/application-structure - Default assistants (the run id is the
graph id) —https://docs.langchain.com/langsmith/assistants - Run a local server / Studio —
https://docs.langchain.com/oss/python/langgraph/local-server useStream
(frontend streaming) —https://www.npmjs.com/package/@langchain/react- Secure passthrough proxy — https://www.npmjs.com/package/langgraph-nextjs-api-passthrough - Deploy the UI on Vercel (Next.js) — https://vercel.com/docs/frameworks/nextjs
Footnotes #
Deploy to Cloud —
"Agent deployments running on Cloud require a Plus plan or above"—https://docs.langchain.com/langsmith/deploy-to-cloud-overview↩ - LangSmith pricing (Developer $0 / Plus $39-seat / Enterprise custom; free-trace tiers; deployment run + uptime rates) —
https://www.langchain.com/pricing↩