![]()
上一课将代理扩展到云端。这一课则将它们带回到单机环境中。到最后,你将拥有一个工作中的工程助理,它能推理、调用工具、读取你的文件并搜索你的文档 — 无需任何云推理调用。
为什么你会想要这样?在实际工程工作中有三个常见原因:
要点是你需要用一个运行在 CPU、GPU 或 NPU 上的 小型语言模型(SLM) 替代前沿的云端模型。本课讲的是如何在这一限制下构建表现良好的代理,而不是假装这限制不存在。
本课将涵盖:
完成本课后,你将能够:
本课假设你已完成之前课程,并熟悉:
你还需要:
requirements.txt 中的包,以及本课所需的 foundry-local-sdk、openai 和 chromadb。前沿云模型有上千亿参数和数据中心支持,而 SLM 有几十亿参数,必须适配你笔记本的内存。这种差异带来了明确的期望。
SLMs 擅长:
SLMs 较弱的方面:
因此,本地代理的制胜策略是:让 SLM 进行编排,让工具承担重活。 模型不需要了解你的代码库;它需要知道何时调用 read_file 和 search_docs。这正好发挥了 SLM 的优势。
flowchart LR
U[开发者] --> A[本地 SLM 代理]
A -->|决定使用哪个工具| T1[读取文件]
A -->|决定使用哪个工具| T2[搜索文档 RAG]
A -->|决定使用哪个工具| T3[分析代码]
T1 --> A
T2 --> A
T3 --> A
A --> R[答复,全设备本地完成]
Microsoft Foundry Local 是一个轻量级运行时,能够在你的机器上下载、管理并服务模型。对我们最重要的功能是它暴露了一个兼容 OpenAI 的 HTTP 端点 — 这意味着你只需更改 base_url,OpenAI SDK 和 Microsoft Agent Framework 的 OpenAI 客户端就能够使用它。你关于构建代理的所有知识都可直接迁移;唯一变化是端点从云端移到 localhost。
Foundry Local 还能根据你的硬件自动选择最优模型版本 — CPU 版本、CUDA/GPU 版本或 NPU 版本 — 省去你为每台机器手动优化。
安装 Foundry Local(参考对应操作系统的文档),然后确认运行正常:
# 安装(示例;请参阅您平台的文档)
winget install Microsoft.FoundryLocal # Windows
# brew install microsoft/foundrylocal/foundrylocal # macOS
# 下载并运行 Qwen 模型,然后启动本地服务
foundry model run qwen2.5-7b-instruct
foundry service status
服务启动后,你就拥有了一个本地兼容 OpenAI 的端点(通常为 http://localhost:PORT/v1)。笔记本使用 foundry-local-sdk 自动发现端点,因此你无需写死端口号。
一个代理只有能够调用工具时才是代理。许多 SLM 可以聊天,但无法可靠地产生规范的工具调用。Qwen 模型经过专门训练以生成函数调用,能够持续输出结构良好的工具调用,这正是将本地聊天模型变成本地代理的关键。
该流程是你已熟悉的标准工具调用循环,只是运行在本地设备上:
sequenceDiagram
participant U as 用户
participant A as Qwen 代理(本地)
participant T as 本地工具
U->>A: "auth.py 做什么?"
A->>A: 决策:调用 read_file
A->>T: read_file("auth.py")
T-->>A: 文件内容
A->>A: 基于内容推理
A-->>U: 解释
文档搜索是本地代理发光发热的地方。你不必指望 SLM 记住你的框架文档,而是将文档嵌入本地向量数据库,让代理按需检索相关段落。
我们使用 Chroma,一个嵌入式向量存储,无需额外服务管理。整个流程均为本地:本地嵌入模型 → 本地向量 → 本地检索 → 本地 SLM。
flowchart TB
D[您的文档 / 代码] --> E[本地嵌入模型]
E --> V[(Chroma 向量数据库 - 本地存储)]
Q[代理查询] --> QE[本地嵌入查询]
QE --> V
V -->|前 k 个片段| A[Qwen 代理]
A --> Ans[有依据的答案]
这是第五课中 Agentic RAG 模式的复现 — 唯一的区别在于每个组件都运行在你的机器上。
MCP 是一种传输协议,而非云服务。MCP 服务器可以作为本地进程运行,通过标准协议通过 stdio 向代理暴露工具。这让你可以离线重用日益丰富的 MCP 服务器生态 — 文件系统访问、git 操作、数据库查询等。
安全姿态不同于云端,但并非不存在:本地 MCP 服务器仍以你的用户权限运行,因此应限制其可访问范围(例如项目目录,而非整个家目录),并将其输出视作输入进行验证。
本地优先不等于只用本地。成熟系统根据敏感度和难度路由:
| 场景 | 运行位置 |
|---|---|
| 敏感代码/数据,或离线时 | 本地 SLM |
| 简单、有界任务 | 本地 SLM(廉价快速) |
| 非敏感数据上的复杂多跳推理 | 云模型 |
| 故障期间的所有任务 | 本地 SLM(优雅降级) |
这呼应了第16课的模型路由思想 —— 不同的是其中一个“模型”是你自己的机器。一个健壮的设计是在云不可用时回退到本地,使代理质量下降,而不是直接失败。
flowchart LR
Q[请求] --> S{敏感或离线?}
S -->|是| L[本地 SLM]
S -->|否| C{需要深度推理?}
C -->|否| L
C -->|是| Cloud[云模型]
L --> Out[响应]
Cloud --> Out
打开 code_samples/17-local-agent-foundry-local.ipynb 并跟随完成。你将构建一个完全运行在工作站上的本地工程助理,它能:
全程无需调用云端推理。
助理通过兼容 OpenAI 的端点连接 Foundry Local,因此代理代码和云端课程几乎一致,仅客户端不同:
from foundry_local import FoundryLocalManager
from openai import OpenAI
# Foundry Local 发现/下载模型并为我们提供本地端点。
manager = FoundryLocalManager(\"qwen2.5-7b-instruct\")
client = OpenAI(base_url=manager.endpoint, api_key=manager.api_key) # api_key 是本地占位符
工具是限定在项目目录内的普通 Python 函数:
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\")
注意沙箱检查 — 即便在本地,读取任意路径的工具依然是安全隐患。笔记本确保所有工具都限定在单一项目根目录内。
在进入作业之前测试你的理解。
1. 给出两个将代理放在本地运行而非云端的具体理由。
2. 在本地代理中,推荐的 SLM 与工具的分工是什么?为什么?
3. 是什么让我们能用 Foundry Local 重用云端代理代码?
4. 为什么特意选择 Qwen 函数调用模型,而非任意 SLM?
5. 在本地 RAG 流程中,哪些组件运行在机器上?
6. 本地 MCP 服务器运行在你的机器上,这是否意味着它自动安全?你还应采取什么预防措施?
7. 描述一个包含本地模型的合理混合路由规则。
8. 运行本课本地代理的现实最低内存需求是多少?更多内存带来什么好处?
将本地工程助理扩展为你选择的小型项目的本地文档审阅助手(如果愿意,可使用本仓库的任一课程文件夹)。
你的提交应包括:
新增 find_todos 工具,扫描项目中的 TODO/FIXME 注释并返回含文件名和行号的列表 — 并保持与 read_file 一致的沙箱检查。
然后写一段简短的文字说明你将把哪些部分迁移到云端,哪些部分保留在本地,以及原因。评分标准是本地组件是否正确连接,以及你的混合推理是否合理——而非模型质量。
在本课中,你构建了一个完全在自己的机器上运行的代理:
这完成了部署的全流程:第16课将代理扩展到了Microsoft Foundry,本课则将其缩减到单个工作站。下一课将关注保持已部署代理的安全。
免责声明: 本文件由 AI 翻译服务 Co-op Translator 翻译完成。尽管我们力求准确,但请注意,自动翻译可能包含错误或不准确之处。原始语言版文件应视为权威来源。对于重要信息,建议使用专业人工翻译。我们对因使用本翻译而产生的任何误解或误释不承担责任。