LangGraph Quickstart
Run a LangGraph application as a named agent, so every model request it makes is signed with its own key and recorded under it.
A LangGraph application runs through Viper as a named agent. It has its own key, it describes itself when it starts, and it names itself on every model request. The Guardian Platform then records each request under that agent, together with a description of the graph that sent it. The Guardian Agent SDK does the describing and the naming.
This page takes you from an empty machine to a signed request you can see in Guardian.
Before you start
- Python 3.10 to 3.14, with the Guardian Agent SDK’s
langchainextra andlangchain-openai. The SDK comes from EQTY Lab’s Cloudsmith repository, with the entitlement token you install Viper with (Package managers). - Viper 0.3.0 or later, installed and pointed at your Agent Gateway. See Install Viper.
- An API key with the Register Agents scope, or the Register Agents permission to get a registration token from Guardian, to enroll the agent. See Register Agents.
- Your own OpenAI API key. The gateway does not hold provider keys; your key passes through it to OpenAI unchanged.
python3 -m venv .venv && . .venv/bin/activate
export VIPER_CLOUDSMITH_TOKEN=<your entitlement token>
PIP_INDEX_URL="https://dl.cloudsmith.io/$VIPER_CLOUDSMITH_TOKEN/eqtylab/prod/python/simple/" \
pip install "eqty-guardian-agent[langchain]"
pip install "langchain-openai>=1.7,<1.8"Coming from the Register Agent dialog in Guardian? The dialog shows the commands for this page’s steps 1 and 2, with your agent’s name, token and gateway address filled in. You still need Before you start (the install) and the agent.py in step 3, and you use your own agent’s name wherever this page says support-bot.
1. Enroll the agent
Give the agent a name and its own key, then register it with the Guardian Platform. The name is 1 to 64 characters of lowercase letters, digits, ., _ or -, starting with a letter or digit.
viper agent add support-bot
GUARDIAN_API_KEY=ak_… viper agent register support-botViper prints the agent’s key, then the agent ID the Guardian Platform minted:
added agent `support-bot`
did:key:z6Mk…
registered agent `support-bot` (did:key:z6Mk…) as urn:uuid:3f2a…If you have no API key, register with a token from Guardian instead: VIPER_PROVISIONING_TOKEN='ggr1.…' viper agent register support-bot. Choosing LangGraph in the Register Agent dialog shows this page’s commands with the token and your gateway address filled in. See Named agents.
Check the enrollment with viper doctor. It confirms the gateway answers and accepts support-bot’s key, and prints a fix for anything that fails. Its warning that the proxy has no key is expected until you start the proxy.
2. Start the proxy
Start a proxy for OpenAI traffic. It loads every enrolled agent when it starts, so start it after enrolling the agent, and restart it after enrolling another. To restart it, stop it with kill %1 (or fg, then Ctrl-C), then run viper proxy again. The proxy also needs a key of its own, which signs any request that names no agent; create it once if you have not already.
viper did add --assign proxy
viper proxy --app proxy --port 8080 \
--gateway-endpoint https://gateway.example.com/v1/openai_api &Replace https://gateway.example.com with your gateway address. The proxy prints its address, http://localhost:8080. If something else already listens on port 8080, the proxy can’t start, and with & its error is easy to miss: pick another --port and set VIPER_PROXY_URL to the address the proxy prints. To confirm it loaded the agent, ask its local agent API:
curl -s http://127.0.0.1:8080/__viper__/v1/agents/support-bot # your agent's name{ "name": "support-bot", "did": "did:key:z6Mk…", "definitions": [], "latestDefinitionCid": null }A 404 with agent_not_enrolled means the name doesn’t match the one you enrolled, or the proxy started before the agent was enrolled; restart it.
3. Run the agent
describe_graph builds your graph with its model routed through the proxy as the agent. It registers the agent’s definition: the compiled graph’s nodes and edges, a fingerprint of each node’s code, the model and its settings, the instructions you pass, and the package versions. Changing the graph, a prompt or a package version gives a new definition.
Save this as agent.py:
import os
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, MessagesState, StateGraph
import guardian_agent as ga
from guardian_agent.langgraph import describe_graph
AGENT = os.environ.get("VIPER_AGENT", "support-bot")
INSTRUCTIONS = "You answer support questions briefly."
# describe_graph calls this with the model routed through the proxy, as AGENT
def build(llm: ChatOpenAI) -> StateGraph[MessagesState]:
def answer(state: MessagesState) -> MessagesState:
return {
"messages": [llm.invoke([SystemMessage(INSTRUCTIONS), *state["messages"]])]
}
graph = StateGraph(MessagesState)
graph.add_node("answer", answer)
graph.add_edge(START, "answer")
graph.add_edge("answer", END)
return graph
app = describe_graph(
build,
name=AGENT,
models={"llm": ChatOpenAI(model="gpt-4o-mini")},
instructions=INSTRUCTIONS,
guardian=ga.Guardian(os.environ.get("VIPER_PROXY_URL", "http://127.0.0.1:8080")),
)
result = app.invoke(
{"messages": [{"role": "user", "content": "Say hello in five words."}]}
)
print(result["messages"][-1].content)Run it as the agent you enrolled:
VIPER_AGENT=support-bot OPENAI_API_KEY=sk-… python agent.pyThe agent reaches the proxy at http://127.0.0.1:8080. Set VIPER_PROXY_URL if yours is elsewhere.
4. Confirm it in Guardian
- Open the Agent Catalog and paste the agent ID from step 1 (
urn:uuid:…) into the search box. The agent is listed with the LangGraph type once its first request lands, and as Custom before that. If you used the Register Agent dialog, its last step updates when the request lands, and links to the agent. - Open the agent. The request appears in its Request Logs, signed with the agent’s key.
- To have project policy apply to the agent and see its traffic in a project, associate it with the project.
What is and is not recorded
Recorded:
- Every model request the graph makes, signed with the agent’s own key, after the SDK checks that its model settings and tools match the definition. The prompts your nodes send aren’t checked.
- The agent definition each request was sent with: the graph’s nodes and edges, a fingerprint of each node’s code, the models and their settings, the instructions, the tools, and the package versions.
- The provenance Viper records for any request: host, git and environment details of the process.
Not recorded:
- Per-step LangGraph state. Node names, run IDs, thread IDs and checkpoint IDs are not attached to individual requests, and conversations aren’t part of the definition.
- Tool traffic. Calls your tools make to other services, such as databases and web APIs, do not go through the proxy and are neither signed nor audited.
- A model the graph builds as it runs. Only the models
describe_graphroutes are signed as the agent. One built as the graph runs is signed as the proxy if it’s pointed at the proxy, and isn’t recorded at all if it calls the provider directly. See Calls the SDK can’t see.
Troubleshooting
| Symptom | What to do |
|---|---|
viper proxy stops with no DID configured for proxy | Create the proxy’s key: viper did add --assign proxy. |
Connection error. from the OpenAI client | Nothing answers at http://127.0.0.1:8080. Start the proxy, or set VIPER_PROXY_URL to the address it printed. |
404 with agent_not_enrolled: agent `…` is not enrolled on this proxy | Set VIPER_AGENT to the exact name you enrolled: the Agent Name in the Register Agent dialog. If you haven’t enrolled it yet, do step 1, then restart the proxy. |
404 with proxy_incompatible: nothing at … serves the Viper agent API | Something other than viper proxy answers at that address, often another service on port 8080. Start the proxy on another --port, and set VIPER_PROXY_URL to the address it prints. |
502 with proxy_incompatible | The proxy’s Viper is older than the SDK needs. Upgrade to Viper 0.3.0 or later (Install Viper). |
OpenAIError: Missing credentials | Set OPENAI_API_KEY. |
Model requests fail with 401 from OpenAI | OPENAI_API_KEY is wrong. The gateway does not add a key. |
Model requests fail with 502 and another code | Viper could not sign the request or reach the gateway; the error’s code and hint say which. See Run Agents. |
Each error reaches you through the OpenAI client, inside LangGraph’s traceback, with the proxy’s code, message and hint in its body. In your own code, ga.proxy_error(error) turns it into the SDK’s exception. The SDK’s Errors reference lists every error, with what to do.
Go further
The Guardian Agent SDK docs cover everything this page leaves out:
- LangGraph graphs: tools, routers, subgraphs, and what
describe_graphrecords and refuses. - LangChain agents: agents built with
create_agent, whose every call is checked against the definition. - Multiple agents: several agents in one process, each signing as itself.
- Test your agents: run them in tests without Viper, keys or a network.
Related
- Deep Agents Quickstart — the same setup for an agent with sub-agents
- OpenShell Quickstart — run an agent in a sandbox where Viper is its only way out
- Run Agents — sidecar mode in general, and troubleshooting for failed requests
- Associated Agents — link the agent to a project so project policy applies
- Agent Configuration — what Viper captures about the agent at the start of each session
- Agent Coverage — how this integration’s coverage compares with the others