Skip to content

Commit 77fe51e

Browse files
feat(langgraph): add the run samples (#988)
* feat(langgraph): add the run samples * add test spec * fix comments
1 parent 14032aa commit 77fe51e

23 files changed

Lines changed: 967 additions & 0 deletions

File tree

‎samples/python/hosted-agents/langgraph/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ This directory contains samples that demonstrate how to use [LangGraph](https://
1414
| 6 | [Files](responses/06-files/) | A LangGraph agent with local filesystem tools and a Foundry-Toolbox `code_interpreter`, demonstrating session-uploaded file handling. |
1515
| 7 | [Human-in-the-Loop](responses/07-human-in-the-loop/) | A LangGraph `StateGraph` that drafts a proposal and pauses for human review via `langgraph.types.interrupt`, serialized as `mcp_approval_request` + `function_call` output items. |
1616
| 8 | [Observability](responses/08-observability/) | A LangGraph agent with GenAI OpenTelemetry tracing enabled via `enable_auto_tracing()`, emitting spans, metrics, and logs to Application Insights. |
17+
| 10 | [Run](responses/10-run/) | A minimal configuration-driven LangGraph agent hosted over the Responses protocol with the `langchain_azure_ai.agents.hosting.run` entrypoint. |
1718

1819
### Invocations API
1920

2021
| # | Sample | Description |
2122
| --- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
2223
| 1 | [Chat](invocations/01-langgraph-chat/) | A minimal LangGraph agent with two local tools, demonstrating session state via `agent_session_id` (URL param / `x-agent-session-id` response header) backed by a LangGraph checkpointer. |
24+
| 3 | [Run](invocations/03-run/) | A minimal configuration-driven LangGraph agent hosted over the Invocations protocol with the `langchain_azure_ai.agents.hosting.run` entrypoint and in-process `MemorySaver` state. |
2325

2426
### Agent-to-Agent (A2A)
2527

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Coding Agent Instructions
2+
3+
This project is a **Microsoft Foundry hosted agent** built with LangGraph and the Invocations protocol. It runs in [Foundry Agent Service](https://learn.microsoft.com/en-us/azure/foundry/agents/concepts/hosted-agents) and uses the configuration-driven `langchain_azure_ai.agents.hosting.run` entrypoint.
4+
5+
## Key files
6+
7+
- `azure.yaml` - Foundry hosted-agent manifest
8+
- `src/langgraph-run-invocations/main.py` - exported LangGraph graph used by the hosting entrypoint
9+
- `src/langgraph-run-invocations/langgraph.json` - graph registry for the run command
10+
- `src/langgraph-run-invocations/requirements.txt` - locked dependencies
11+
12+
## Development workflow
13+
14+
```bash
15+
azd ai agent run --no-client
16+
azd ai agent invoke --local '{"message": "your message"}'
17+
azd deploy
18+
azd ai agent invoke '{"message": "your message"}'
19+
```
20+
21+
## Microsoft Foundry Skill
22+
23+
This project was built with the microsoft-foundry skill. Before working on or answering questions about Foundry agents, read that skill first.
24+
25+
Install the skill with:
26+
27+
```bash
28+
npx skills add https://github.com/microsoft/azure-skills --skill microsoft-foundry
29+
```
30+
31+
## References
32+
33+
- [Hosted agents overview](https://learn.microsoft.com/en-us/azure/foundry/agents/concepts/hosted-agents)
34+
- [LangGraph](https://langchain-ai.github.io/langgraph/)
35+
- [Microsoft Foundry Skill](https://learn.microsoft.com/en-us/azure/foundry/how-to/develop/use-microsoft-foundry-skill)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# CLAUDE.md
2+
3+
This project uses [AGENTS.md](./AGENTS.md) as the single source of truth for coding agent instructions. The import below loads it into Claude Code's context.
4+
5+
@AGENTS.md
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# What this sample demonstrates
2+
3+
A [LangGraph](https://langchain-ai.github.io/langgraph/) agent hosted using the **Invocations protocol** with session management. It uses the configuration-driven `langchain_azure_ai.agents.hosting.run` entrypoint instead of constructing an `InvocationsHostServer` in application code.
4+
5+
> **No agent code changes are required to migrate an existing LangChain
6+
> agent to this approach.** Keep the existing graph implementation as-is,
7+
> point `langgraph.json` at its exported graph, and launch the hosting
8+
> entrypoint with the desired protocol.
9+
10+
Multi-turn continuity is provided by a LangGraph `MemorySaver`
11+
checkpointer: the resolved `agent_session_id` is forwarded to the graph
12+
as `RunnableConfig.configurable.thread_id`, so each session's history is
13+
preserved in process memory.
14+
15+
## How It Works
16+
17+
### Graph and model integration
18+
19+
The agent uses `langchain_openai.ChatOpenAI` with an Azure bearer token
20+
provider from `DefaultAzureCredential` and an OpenAI-compatible endpoint
21+
from `azure.ai.projects.AIProjectClient` (`az login` is enough for local
22+
development). The graph is the same no-tool `create_agent` graph with
23+
`MemorySaver` used by the other minimal Invocations samples in this repo.
24+
25+
See [src/langgraph-run-invocations/main.py](src/langgraph-run-invocations/main.py)
26+
for the graph and [src/langgraph-run-invocations/langgraph.json](src/langgraph-run-invocations/langgraph.json)
27+
for its entrypoint configuration.
28+
29+
### Migrating an Existing Agent
30+
31+
An existing LangChain agent that exports a compiled graph does not need a
32+
hosting wrapper, an `InvocationsHostServer` import, or a new `main()`
33+
function. Add a `langgraph.json` file that references the existing graph
34+
symbol, then use the command shown below. The agent's model, tools,
35+
prompts, state, checkpointer, and graph code remain unchanged.
36+
37+
### Agent Hosting
38+
39+
The `langgraph.json` file maps the `agent` name to the compiled graph in
40+
`main.py`. The hosting entrypoint loads that graph and exposes it through
41+
the protocol selected by the required `--protocol` argument. This sample
42+
selects `invocations` in both its local command and Docker image.
43+
44+
## Option 1: Azure Developer CLI (`azd`)
45+
46+
### Prerequisites
47+
48+
1. **Azure Developer CLI (`azd`)** — [Install azd](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/install-azd)
49+
2. Install the Foundry extension:
50+
51+
```bash
52+
azd ext install microsoft.foundry
53+
```
54+
55+
3. Authenticate:
56+
57+
```bash
58+
azd auth login
59+
```
60+
61+
### Initialize the agent project
62+
63+
No cloning required. Create a new folder and initialize from the manifest:
64+
65+
```bash
66+
mkdir hosted-langgraph-agent && cd hosted-langgraph-agent
67+
azd ai agent init -m https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/langgraph/invocations/03-run/azure.yaml
68+
```
69+
70+
Follow the prompts to configure your Foundry project and model deployment.
71+
72+
### Provision Azure resources (if needed)
73+
74+
If you don't already have a Foundry project and model deployment:
75+
76+
```bash
77+
azd provision
78+
```
79+
80+
### Run the agent locally
81+
82+
```bash
83+
azd ai agent run --no-client
84+
```
85+
86+
The agent host will start on `http://localhost:8088`.
87+
88+
### Invoke the local agent
89+
90+
In a separate terminal, invoke the running agent:
91+
92+
```bash
93+
azd ai agent invoke --local '{"message": "Hello!"}'
94+
```
95+
96+
Or invoke directly with curl. The returned `x-agent-session-id` header is used for multi-turn conversations:
97+
98+
```bash
99+
curl -i -X POST http://localhost:8088/invocations \
100+
-H "Content-Type: application/json" \
101+
-d '{"message": "Hello!"}'
102+
```
103+
104+
### Deploy to Foundry
105+
106+
Once tested locally, deploy to Microsoft Foundry:
107+
108+
```bash
109+
azd deploy
110+
```
111+
112+
## Option 2: VS Code (Foundry Toolkit)
113+
114+
### Prerequisites
115+
116+
1. **VS Code** with the **[Foundry Toolkit](https://marketplace.visualstudio.com/items?itemName=ms-windows-ai-studio.windows-ai-studio)** extension installed.
117+
2. Install the **[Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python)** extension pack if you want to debug the sample locally.
118+
119+
### Set up the Python virtual environment
120+
121+
- Open the Command Palette (`Ctrl+Shift+P`) and run **Python: Create Environment...** to create a virtual environment in the project.
122+
- Ensure `pip` is version 26.1 or newer (check with `pip --version`). Older versions fail to resolve this sample's dependencies. Upgrade if needed:
123+
124+
```bash
125+
python -m pip install --upgrade pip
126+
```
127+
128+
- Install dependencies in the virtual environment:
129+
130+
```bash
131+
pip install -r src/langgraph-run-invocations/requirements.txt
132+
```
133+
134+
### Run locally
135+
136+
```bash
137+
cd src/langgraph-run-invocations
138+
python -m langchain_azure_ai.agents.hosting.run --protocol invocations
139+
```
140+
141+
Then invoke it:
142+
143+
```bash
144+
curl -X POST http://127.0.0.1:8088/invocations \
145+
-H "Content-Type: application/json" \
146+
-d '{"message": "Hello!"}'
147+
```
148+
149+
## Troubleshooting
150+
151+
### Azure OpenAI Permission Denied (401)
152+
153+
This sample calls the project's model endpoint through LangChain. The hosted agent's managed identity needs the **Foundry User** role on the project. Assign that role at the project scope and retry after role propagation completes.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
2+
3+
requiredVersions:
4+
extensions:
5+
azure.ai.agents: '>=1.0.0-beta.4'
6+
name: langgraph-run-invocations
7+
services:
8+
ai-project:
9+
host: azure.ai.project
10+
deployments:
11+
- name: gpt-5.4-mini
12+
model:
13+
format: OpenAI
14+
name: gpt-5.4-mini
15+
version: '2026-03-17'
16+
sku:
17+
name: GlobalStandard
18+
capacity: 10
19+
langgraph-run-invocations:
20+
host: azure.ai.agent
21+
metadata:
22+
tags:
23+
- AI Agent Hosting
24+
- Invocations Protocol
25+
- LangGraph
26+
- LangChain
27+
- Tool Calling
28+
- Python
29+
project: src/langgraph-run-invocations
30+
language: python
31+
codeConfiguration:
32+
runtime: python_3_13
33+
entryPoint: '-m langchain_azure_ai.agents.hosting.run --protocol invocations'
34+
uses:
35+
- ai-project
36+
kind: hosted
37+
name: langgraph-run-invocations
38+
displayName: LangGraph Run (Invocations)
39+
description: 'A minimal configuration-driven LangGraph agent hosted on Foundry over the Invocations protocol using the langchain_azure_ai.agents.hosting.run entrypoint.'
40+
protocols:
41+
- protocol: invocations
42+
version: 2.0.0
43+
env:
44+
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
45+
container:
46+
resources:
47+
cpu: '0.5'
48+
memory: 1Gi
49+
infra:
50+
provider: microsoft.foundry
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.venv
2+
__pycache__
3+
*.pyc
4+
*.pyo
5+
*.pyd
6+
.Python
7+
.env
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Foundry project endpoint — auto-injected in hosted containers.
2+
# Only set manually if running without `azd ai agent run`.
3+
FOUNDRY_PROJECT_ENDPOINT=
4+
5+
# Model deployment name — must match a deployment in your Foundry project.
6+
AZURE_AI_MODEL_DEPLOYMENT_NAME=
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM python:3.12-slim
2+
3+
WORKDIR /app
4+
5+
COPY . user_agent/
6+
WORKDIR /app/user_agent
7+
8+
RUN python -m pip install --upgrade pip && \
9+
if [ -f requirements.txt ]; then \
10+
python -m pip install -r requirements.txt; \
11+
else \
12+
echo "No requirements.txt found"; \
13+
fi
14+
15+
EXPOSE 8088
16+
17+
CMD ["python", "-m", "langchain_azure_ai.agents.hosting.run", "--protocol", "invocations"]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://langgra.ph/schema.json",
3+
"dependencies": ["."],
4+
"graphs": {
5+
"agent": "./main.py:graph"
6+
},
7+
"env": ".env"
8+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""Sample 03 - configuration-driven Invocations API host.
2+
3+
Defines the same ``create_agent`` graph with ``MemorySaver`` as sample 01.
4+
The ``langchain_azure_ai.agents.hosting.run`` module loads the graph from
5+
``langgraph.json`` and hosts it with the selected protocol.
6+
7+
Required environment variables (set in `.env` or your shell):
8+
9+
FOUNDRY_PROJECT_ENDPOINT e.g. https://<acct>.services.ai.azure.com/api/projects/<proj>
10+
AZURE_AI_MODEL_DEPLOYMENT_NAME e.g. gpt-5.4-mini (defaults to "gpt-5.4-mini")
11+
PORT optional, defaults to 8088
12+
13+
Run::
14+
15+
az login
16+
cp .env.example .env # then edit the values
17+
python -m langchain_azure_ai.agents.hosting.run --protocol invocations
18+
19+
Then in another terminal:
20+
21+
curl -i -X POST http://127.0.0.1:8088/invocations \
22+
-H 'Content-Type: application/json' \
23+
-d '{"message":"My name is Alice."}'
24+
"""
25+
from __future__ import annotations
26+
27+
import os
28+
29+
from azure.ai.projects import AIProjectClient
30+
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
31+
from dotenv import load_dotenv
32+
from langchain.agents import create_agent
33+
from langchain_openai import ChatOpenAI
34+
from langgraph.checkpoint.memory import MemorySaver
35+
36+
from opentelemetry import trace
37+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
38+
from opentelemetry.sdk.trace import TracerProvider
39+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
40+
41+
from langchain_azure_ai.callbacks.tracers import enable_auto_tracing
42+
43+
load_dotenv()
44+
45+
_AZURE_AI_SCOPE = "https://ai.azure.com/.default"
46+
47+
48+
def _build_chat_model() -> ChatOpenAI:
49+
project_endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"].rstrip("/")
50+
deployment = os.environ.get("AZURE_AI_MODEL_DEPLOYMENT_NAME") or "gpt-5.4-mini"
51+
credential = DefaultAzureCredential()
52+
project = AIProjectClient(endpoint=project_endpoint, credential=credential)
53+
openai_client = project.get_openai_client()
54+
token_provider = get_bearer_token_provider(credential, _AZURE_AI_SCOPE)
55+
56+
return ChatOpenAI(
57+
model=deployment,
58+
base_url=str(openai_client.base_url),
59+
api_key=token_provider,
60+
use_responses_api=True,
61+
output_version="responses/v1",
62+
)
63+
64+
65+
def _configure_tracing() -> None:
66+
if os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"):
67+
provider = TracerProvider()
68+
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
69+
trace.set_tracer_provider(provider)
70+
enable_auto_tracing()
71+
else:
72+
enable_auto_tracing(auto_configure_azure_monitor=True)
73+
74+
75+
_configure_tracing()
76+
graph = create_agent(_build_chat_model(), tools=[], checkpointer=MemorySaver())

0 commit comments

Comments
 (0)