构建本地 AI 智能体
本地 AI 智能体是一个完全运行在你自己硬件上的自主循环:一个开放权重模型(由 Ollama 或 LM Studio 提供服务)决定要做什么、调用你给它的工具、读取结果,并持续运行直到任务完成——而且没有任何数据离开你的机器。没有云 API、没有按次计费、无需联网。代价是:一个小到能在笔记本电脑上运行的模型,在困难推理和长周期规划上比前沿模型更弱,而且你要为它的可靠性和安全性负责。本页讲述本地智能体的诚实理由、最小架构、真正在本地运行的东西,以及打造你第一个智能体的现实路径。
- 知道为什么你会想构建一个在本地运行的智能体——以及相对云 API 智能体的诚实权衡
- 理解最小架构:本地模型 + 工具调用循环 + 工具 + 护栏/停止条件
- 挑选一个真正能做工具调用/智能体工作的本地模型
- 了解哪些智能体框架可以通过指向本地端点在本地运行(LangGraph、CrewAI、OpenAI Agents SDK)
- 遵循一条从单次工具调用到带护栏循环的“由简入繁”路径
- 对智能体做沙箱隔离和预算上限,让自主循环无法造成真正的破坏
为什么要构建本地智能体(以及何时不该)
一个普通的工具使用智能体调用的是云模型。而本地智能体把那次云调用换成了运行在你自己机器上的模型。你放弃一些能力,并承担一些运维负担;作为交换,你得到四样其他方式很难获得的东西:
- 隐私——提示词、工具输入和工具输出永远不离开机器。这正是身处受监管、敏感或气隙隔离环境的团队构建本地智能体的全部原因:数据在物理上无法送到第三方。
- 离线——无需联网、无 API 依赖、不受服务商宕机影响。智能体就是你磁盘上的文件;它能在飞机上或防火墙后运行。
- 无按次成本——一个智能体循环每个任务可能触发几十次模型调用。在本地这些调用是“免费”的(你付出的是电费和硬件,而非 token),所以你可以让它反复迭代而不必盯着计费表。
- 完全掌控——固定一个确切的模型版本、自定义行为,运行时不受速率限制或服务条款变动的意外影响。
诚实的权衡取舍——在你投入之前请清醒看待这些:
- **能力差距。**智能体最难的部分是推理:规划多步工作、从失败的工具调用中恢复、知道何时该停下。一个你能在笔记本电脑上运行的模型(大约 1B–14B 参数)在这方面明显弱于前沿模型。简单、范围明确的循环在本地运行得很好;长周期、开放式的任务恰恰是本地智能体最常出轨的地方。
- **可靠性和安全性由你负责。**没有服务商为你过滤、监控或设护栏。如果智能体无限循环、调用了错误的工具,或采取了破坏性行动,那是你的设计问题。(见下方警告——这是人们最容易低估的部分。)
- **硬件限制。**更大、更聪明的模型需要比大多数机器更多的 RAM/VRAM。你通常是在选择你的硬件能运行的最大有能力模型,而不是现存最好的模型。
一条经久不衰的经验法则:**从本地起步,当任务需要时再升级。**把本地智能体用于私密/离线/规模化廉价的工作和范围明确的循环;当任务确实需要额外推理能力时,再动用前沿 API 智能体。下面的架构无论哪种方式都完全相同——只是端点变了——所以你可以在本地做原型,之后再换模型。
最小架构
把智能体剥到核心,就只有四个部分。其余一切都是在这之上的便利功能。
┌─────────────────────────────────────────────┐
│ │
│ 1. LOCAL MODEL ──► decides next action │
│ (Ollama / LM Studio, tool-capable) │
│ │ │
│ ▼ │
│ 2. TOOL-CALLING LOOP │
│ parse the model's tool request, │
│ run it, feed the result back │
│ │ │
│ ▼ │
│ 3. TOOLS ──► search / read file / │
│ run code / call an API (your code) │
│ │ │
│ ▼ │
│ 4. GUARDRAIL / STOP CONDITION │
│ max steps, budget, approval gate, │
│ "done" check ──► exit the loop │
│ │
└─────────────────────────────────────────────┘
- **一个支持工具调用的本地模型。**该模型必须能发出调用工具的结构化请求(即函数调用),而不仅仅是聊天。Ollama 通过它的 API 以及在
http://localhost:11434/v1上的 OpenAI 兼容端点暴露此功能,因此任何会说 OpenAI 格式的框架都能驱动一个本地模型。 - **工具调用循环。**智能体的核心:把对话发给模型,看它是否请求调用工具,运行那个工具,追加结果,然后重复。当模型不请求工具而直接回答时,循环结束。
- **工具。**你暴露给模型的普通函数——搜索网络、读取文件、运行 shell 命令、查询数据库、调用 API。每个工具都有一个名称、一段描述和一个带类型的输入 schema,好让模型知道何时以及如何使用它。
- 一个护栏/停止条件。对自主性而言不可妥协。至少要有一个最大步数上限,让循环无法永远运行;此外——对任何会写入、删除、花钱或发送的操作——还要有一个审批门或一个沙箱。没有这个,你拥有的就不是智能体,而是一个能访问文件的死循环。
第 2 步里的循环确实很小。这里用 Python 伪代码针对本地 Ollama 端点展示它:
一个最小的本地智能体循环(Python 伪代码,指向本地 Ollama)
from openai import OpenAI
# Point the OpenAI client at your LOCAL Ollama endpoint — nothing leaves the machine
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
tools = [{
"type": "function",
"function": {
"name": "read_file",
"description": "Read a UTF-8 text file and return its contents",
"parameters": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
},
}]
def run_tool(name, args):
if name == "read_file":
# GUARDRAIL: only allow reads inside a sandboxed directory
return safe_read(args["path"])
raise ValueError(f"unknown tool: {name}")
messages = [{"role": "user", "content": "Summarize ./notes/today.md"}]
for step in range(8): # GUARDRAIL: hard step cap
resp = client.chat.completions.create(
model="llama3.1", messages=messages, tools=tools,
)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls: # STOP: model answered, we're done
print(msg.content)
break
for call in msg.tool_calls:
result = run_tool(call.function.name, json.loads(call.function.arguments))
messages.append({
"role": "tool", "tool_call_id": call.id, "content": str(result),
})
else:
print("Stopped: hit the step cap without finishing.")这就是全部模式。框架在这之上加了记忆、重试、多智能体编排、追踪和结构化状态——但它们中的每一个都是这个循环的更健壮版本。
哪些本地模型适合智能体/工具使用工作
并非每个开放权重模型都能驱动一个智能体。门槛是可靠的工具调用:模型必须能稳定发出格式正确的工具请求、挑选正确的工具,并且不臆造参数。选择时用两个筛选条件:
- **它必须是一个支持工具的模型。**Ollama 会给这些打标签——浏览 Tools 分类获取当前列表,而不要想当然。常被提及在本地工具使用上表现扎实的模型包括 Qwen 和 Llama 的指令微调系列;具体最佳选择每个季度都在变。
- **它必须适配你的硬件并为上下文留出余地。**智能体循环会累积很长的消息历史(每次工具结果都会被追加),所以你既需要权重也需要内存里充裕的上下文窗口。一个能舒适装下并快速运行的较小模型,往往胜过一个换页到磁盘、在循环中途卡住的较大模型。
决定性的一步不是读基准分数——而是拿你自己任务的一个小型评测去跑两三个候选模型。一个在排行榜上登顶的模型,在你智能体所需的具体工具上仍可能不可靠。要在你自己的循环上度量。
可在本地运行的框架
你可以手写上面的循环,对于第一个智能体来说这是很好的学习方式。但对于任何正式的东西,框架会给你重试、记忆、多智能体协调和追踪。关键事实是:主流的智能体框架都是模型无关的——只要你把它们指向正确的端点,它们不在乎模型是在云端还是在 localhost 上。
- LangGraph——一个用于有状态智能体的低层编排框架(持久执行、持久化、人在环中)。模型无关;通过 LangChain 的 Ollama 集成把它接到本地模型,无需任何变通手段。当你需要对智能体的状态图进行显式控制时很合适。
- CrewAI——一个用于编排一个或多个基于角色的智能体(“crews”)的更高层框架。通过 LiteLLM 实现模型无关;用
LLM(model="ollama/llama3.1", base_url="http://localhost:11434")把智能体指向本地模型。当你想快速组合多个协作智能体时很合适。 - OpenAI Agents SDK——一个轻量级的多智能体框架。尽管名字如此,它其实是服务商无关的:通过它的 LiteLLM 集成,你可以把它指向一个本地 Ollama 模型而非 OpenAI 的模型。当你想在本地后端上获得 OpenAI 的智能体使用体验时很合适。
挑一个框架并把它学透,而不是三个都浅尝辄止。概念(智能体、工具、循环、状态)是可迁移的;API 只是细节。
构建你的第一个本地智能体
一条现实的路径会分成刻意的几步,从“完全没有循环”走到“带护栏的自主循环”。别跳到第 4 步——人们在本地智能体上遇到的多数失败,都来自太早给一个弱模型太多自由。
- 安装 Ollama(见“在本地运行模型”),然后拉取一个带工具标签的模型,例如 ollama pull llama3.1。确认它在 http://localhost:11434 上提供服务,且 ollama list 能看到它。还没有智能体——只是一个你能调用的模型。
- 发送一个只定义了一个工具的单次请求(例如一个 get_time 或 read_file 函数),检查模型是否真的返回一个格式正确、参数有效的工具调用。如果一个模型连一次干净的工具调用都做不稳,它就撑不过一个循环——现在就换模型,别等以后。
- 加上上面 PromptCard 里的“运行—执行—回传”循环,配一个硬性最大步数上限(从 6–8 起步)。给它一个小而范围明确的任务,工具只读。盯着每一步打印,好看到模型的推理,及时抓住它兜圈或误用工具。
- 只在此时才引入会改变状态的工具(写文件、运行命令、调用花钱的 API)。把每一个都放在一个审批提示之后,或在沙箱/容器里运行,并加上预算或时钟上限。刻意测试各种失败模式:喂给它一个它无法完成的任务,确认它能干净地停下。
- 一旦手写循环能用,就把它移植到 LangGraph、CrewAI 或指向你本地端点的 OpenAI Agents SDK。你会免费得到重试、记忆和多智能体编排——而模型仍然待在原地,在你的机器上。
- 一个带工具的本地智能体仍然可以采取真实的行动——给它做沙箱隔离、对破坏性步骤要求审批,并对它的循环/预算设上限。
自测一下
自测一下
0/4- 本地智能体就是标准的工具使用循环,只是把云模型换成了你机器上的开放权重模型——私密、离线、可免费迭代。
- 最小架构 = 支持工具的本地模型 + 工具调用循环 + 工具 + 护栏/停止条件。循环本身很小。
- Ollama 的 OpenAI 兼容端点(/v1)支持工具调用,所以任何 OpenAI 格式的框架都能驱动本地模型。
- LangGraph、CrewAI 和 OpenAI Agents SDK 都是模型无关的——把它们指向一个本地端点而非云端。
- 挑一个适配你硬件的、支持工具的模型,然后用你自己任务的一个小型评测来决定——而不是排行榜。
- 对能力差距要诚实,并对安全性负责:给循环和预算设上限、给工具做沙箱、对任何破坏性操作要求审批。
- 从简单起步:一次干净的工具调用 → 有界的只读循环 → 带护栏的破坏性工具 →(可选)一个框架。