![]()
The previous lesson scaled agents up into the cloud. This one brings them down onto a single machine. By the end you will have a working engineering assistant that reasons, calls tools, reads your files, and searches your documentation — without a single cloud inference call.
Why would you want that? Three reasons that come up constantly in real engineering work:
The catch is that you are trading a frontier cloud model for a Small Language Model (SLM) running on your CPU, GPU, or NPU. This lesson is about building agents that are good within that constraint rather than pretending the constraint isn’t there.
This lesson will cover:
After completing this lesson, you will know how to:
This lesson assumes you have completed the earlier lessons and are comfortable with:
You will also need:
requirements.txt, plus foundry-local-sdk, openai, and chromadb for this lesson.A frontier cloud model has hundreds of billions of parameters and a data centre behind it. An SLM has a few billion parameters and has to fit in your laptop’s RAM. That difference sets clear expectations.
SLMs are good at:
SLMs are weaker at:
The winning strategy for local agents is therefore: let the SLM orchestrate, and let tools do the heavy lifting. The model doesn’t need to know your codebase — it needs to know when to call read_file and search_docs. That plays directly to an SLM’s strengths.
flowchart LR
U[Developer] --> A[Local SLM Agent]
A -->|decides which tool| T1[read_file]
A -->|decides which tool| T2[search_docs RAG]
A -->|decides which tool| T3[analyze_code]
T1 --> A
T2 --> A
T3 --> A
A --> R[Answer, fully on-device]
Microsoft Foundry Local is a lightweight runtime that downloads, manages, and serves models entirely on your machine. Its most important feature for us is that it exposes an OpenAI-compatible HTTP endpoint — which means the OpenAI SDK and the Microsoft Agent Framework’s OpenAI client work against it with only a change of base_url. Everything you learned about building agents transfers directly; only the endpoint moves from the cloud to localhost.
Foundry Local also picks the best build of a model for your hardware automatically — a CPU build, a CUDA/GPU build, or an NPU build — so you don’t hand-optimise per machine.
Install Foundry Local (see the documentation for your OS), then confirm it works:
# Install (example; follow the docs for your platform)
winget install Microsoft.FoundryLocal # Windows
# brew install microsoft/foundrylocal/foundrylocal # macOS
# Download and run a Qwen model, then start the local service
foundry model run qwen2.5-7b-instruct
foundry service status
Once the service is running you have a local, OpenAI-compatible endpoint (typically http://localhost:PORT/v1). The notebook uses the foundry-local-sdk to discover the endpoint automatically, so you don’t have to hard-code the port.
An agent is only an agent if it can call tools. Many SLMs can chat but produce unreliable, malformed tool calls. Qwen models are trained for function calling and emit well-formed tool-call structures consistently — which is exactly what turns a local chat model into a local agent.
The flow is the standard tool-calling loop you already know, just running on-device:
sequenceDiagram
participant U as User
participant A as Qwen Agent (local)
participant T as Local Tool
U->>A: "What does auth.py do?"
A->>A: Decide: call read_file
A->>T: read_file("auth.py")
T-->>A: file contents
A->>A: Reason over contents
A-->>U: Explanation
Documentation search is where local agents earn their keep. Instead of hoping the SLM memorised your framework’s docs, you embed those docs into a local vector database and let the agent retrieve the relevant chunks on demand.
We use Chroma, an embedded vector store that runs in-process with no server to manage. The pipeline is entirely local: local embedding model → local vectors → local retrieval → local SLM.
flowchart TB
D[Your docs / code] --> E[Local embedding model]
E --> V[(Chroma vector DB - on disk)]
Q[Agent query] --> QE[Embed query locally]
QE --> V
V -->|top-k chunks| A[Qwen agent]
A --> Ans[Grounded answer]
This is the same Agentic RAG pattern from Lesson 5 — the only change is that every component runs on your machine.
MCP is a transport, not a cloud service. An MCP server can run as a local process on stdio, exposing tools to your agent over the standard protocol. This lets you reuse the growing ecosystem of MCP servers — filesystem access, git operations, database queries — entirely offline.
The security posture is different from the cloud, but not absent: a local MCP server still runs with your user’s permissions, so scope what it can touch (a project directory, not your whole home folder) and treat its outputs as inputs to validate.
Local-first does not mean local-only. Mature systems route by sensitivity and difficulty:
| Situation | Where it runs |
|---|---|
| Sensitive code / data, or offline | Local SLM |
| Simple, bounded task | Local SLM (cheap, fast) |
| Hard multi-hop reasoning on non-sensitive data | Cloud model |
| Everything, during an outage | Local SLM (graceful degradation) |
This mirrors the model routing idea from Lesson 16 — except one of the “models” is now your own machine. A robust design falls back to local when the cloud is unavailable, so the agent degrades in quality rather than failing outright.
flowchart LR
Q[Request] --> S{Sensitive or offline?}
S -->|yes| L[Local SLM]
S -->|no| C{Needs deep reasoning?}
C -->|no| L
C -->|yes| Cloud[Cloud model]
L --> Out[Response]
Cloud --> Out
Open code_samples/17-local-agent-foundry-local.ipynb and work through it. You will build a local engineering assistant that runs entirely on your workstation and can:
No cloud inference is used at any point.
The assistant connects to Foundry Local through the OpenAI-compatible endpoint, so the agent code looks almost identical to the cloud lessons — only the client changes:
from foundry_local import FoundryLocalManager
from openai import OpenAI
# Foundry Local discovers/downloads the model and gives us a local endpoint.
manager = FoundryLocalManager(\"qwen2.5-7b-instruct\")
client = OpenAI(base_url=manager.endpoint, api_key=manager.api_key) # api_key is a local placeholder
The tools are ordinary Python functions scoped to a project directory:
def read_file(path: str) -> str:
\"\"\"Read a file, but only inside the sandboxed project directory.\"\"\"
full = (PROJECT_ROOT / path).resolve()
if PROJECT_ROOT not in full.parents and full != PROJECT_ROOT:
return \"Access denied: path is outside the project directory.\"
return full.read_text(encoding=\"utf-8\")
Note the sandbox check — even locally, a tool that reads arbitrary paths is a liability. The notebook keeps every tool scoped to a single project root.
Test your understanding before moving to the assignment.
1. Give two concrete reasons to run an agent locally instead of in the cloud.
2. What is the recommended division of labour between an SLM and its tools in a local agent, and why?
3. What makes it possible to reuse cloud agent code with Foundry Local?
4. Why do we specifically use a Qwen function-calling model rather than any SLM?
5. In the local RAG pipeline, which components run on the machine?
6. A local MCP server runs on your machine. Does that make it automatically safe? What precaution should you still take?
7. Describe a sensible hybrid routing rule that includes a local model.
8. What is a realistic minimum RAM figure for running the local agent in this lesson, and what does more RAM buy you?
Extend the local engineering assistant into a local documentation reviewer for a small project of your choice (use one of this repo’s lesson folders if you like).
Your submission should:
find_todos tool that scans the project for TODO/FIXME comments and returns them with file and line number — keeping the same sandbox check as read_file.Then write a short paragraph on what you would move to the cloud and what you would keep local for this reviewer, and why. You are assessed on whether the local components are wired together correctly and whether your hybrid reasoning is sound — not on model quality.
In this lesson you built an agent that runs entirely on your own machine:
This completes the deployment arc: Lesson 16 scaled agents up into Microsoft Foundry, and this lesson scaled them down onto a single workstation. The next lesson turns to keeping deployed agents secure.