# Session 9 Cheat Sheet — Agent Servers

> Source: <https://gist.github.com/donbr/be86b6da2cff3d9fbae0de3f8c5fa985>
> Published: 2026-07-01 00:10:45+00:00

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.js`frontend/`

).No notebook— Q1/Q2 are answered in`README.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/*`

.

``` php
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/](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](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.

``` python
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](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](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](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 *personal*org is

**Developer**(free, no cloud deploy); a

*team/shared*org 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:

[pricing](https://www.langchain.com/pricing)

.

[2](https://gist.github.com/starred.atom#user-content-fn-pricing-a8ef8788b69bb001303b553fbcbe337c)| 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](https://www.npmjs.com/package/@langchain/react)

```
const { messages, submit, isLoading } = 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](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](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
*be*your 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 are`LANGGRAPH_API_URL`

/`LANGSMITH_API_KEY`

deliberately*not*prefixed while`NEXT_PUBLIC_API_URL`

is? - Trace one request: browser →
`/api/*`

→ ? Where does`initApiPassthrough`

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 runs*after*the 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
*back*to 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 limit*first*— 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
*see*the judge call? - Reflect (the README asks): is the loop's
*logic*any 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
*another*user'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](https://docs.langchain.com/langsmith/billing) - Deployment environments (Cloud vs standalone vs self-hosted; plan requirements) —
[https://docs.langchain.com/langsmith/deployment](https://docs.langchain.com/langsmith/deployment) - Local development & testing (
`langgraph dev`

vs`langgraph up`

) —[https://docs.langchain.com/langsmith/local-dev-testing](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](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](https://docs.langchain.com/langsmith/local-dev-testing#langgraph-up)- LangGraph CLI
`up`

/`build`

/`dockerfile`

commands —[https://docs.langchain.com/langsmith/cli](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](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](https://docs.langchain.com/langsmith/cli) - Application structure (
`langgraph.json`

) —[https://docs.langchain.com/langsmith/application-structure](https://docs.langchain.com/langsmith/application-structure) - Default assistants (the run id is the
**graph id**) —[https://docs.langchain.com/langsmith/assistants](https://docs.langchain.com/langsmith/assistants) - Run a local server / Studio —
[https://docs.langchain.com/oss/python/langgraph/local-server](https://docs.langchain.com/oss/python/langgraph/local-server) `useStream`

(frontend streaming) —[https://www.npmjs.com/package/@langchain/react](https://www.npmjs.com/package/@langchain/react)- Secure passthrough proxy —
[https://www.npmjs.com/package/langgraph-nextjs-api-passthrough](https://www.npmjs.com/package/langgraph-nextjs-api-passthrough) - Deploy the UI on Vercel (Next.js) —
[https://vercel.com/docs/frameworks/nextjs](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](https://docs.langchain.com/langsmith/deploy-to-cloud-overview)[↩](https://gist.github.com/starred.atom#user-content-fnref-plus-a8ef8788b69bb001303b553fbcbe337c) -
LangSmith pricing (Developer $0 / Plus $39-seat / Enterprise custom; free-trace tiers; deployment run + uptime rates) —

[https://www.langchain.com/pricing](https://www.langchain.com/pricing)[↩](https://gist.github.com/starred.atom#user-content-fnref-pricing-a8ef8788b69bb001303b553fbcbe337c)
