【本地AI进阶:Function Calling与MCP协议完全指南——让AI Agent帮你自动执行任务】
title: 本地AI进阶:Function Calling与MCP协议完全指南——让AI Agent帮你自动执行任务
tags: AI Agent,Function Calling,MCP协议,OpenWebUI,工具调用,本地AI,自动化,Ollama
category: 人工智能
本地AI进阶:Function Calling与MCP协议完全指南——让AI Agent帮你自动执行任务
本文是《本地AI配置完全攻略》系列第8篇。前7篇分别介绍了DeepSeek部署、Page Assist、OpenWebUI、联网搜索、知识库RAG、多模态语音、手机远程访问。本篇介绍如何让本地AI从"对话工具"进化为能自主调用工具的 AI Agent。
场景:你的本地AI已经能聊天、搜索、读文档,但它还只能"说"不能"做"。本篇教你用 Function Calling 和 MCP 协议,让AI能自主调用工具、执行任务、自动化工作流——全部在本地运行。
目录
- AI Agent 是什么?为什么需要它?
- Function Calling 原理与协议标准
- 本地模型工具调用能力对比
- OpenWebUI 中配置 Function Calling
- 实战:编写自定义工具函数
- MCP 协议:连接一切的标准接口
- OpenWebUI + MCP 完整配置
- 实战案例:文件管理 Agent
- 定时任务:让 Agent 自动执行
- 安全与权限控制
- 总结与下一步
1. AI Agent 是什么?为什么需要它?
1.1 传统对话 AI 的局限
| 能力维度 | 传统对话AI | AI Agent |
|---|---|---|
| 信息处理 | ✅ 理解和生成文本 | ✅ + 能操作外部系统 |
| 任务执行 | ❌ 只能建议 | ✅ 能实际执行 |
| 多步骤规划 | ❌ 单轮对话 | ✅ 自主规划步骤 |
| 工具使用 | ❌ 无法调用 | ✅ 自主选择和调用工具 |
| 持续运行 | ❌ 需人工触发 | ✅ 可定时/事件触发 |
1.2 AI Agent 架构
┌─────────────────────────────────────────────┐
│ AI Agent 系统 │
├─────────────────────────────────────────────┤
│ 🧠 LLM 核心(DeepSeek-R1 / Qwen2.5) │
│ ↓ 生成工具调用决策 │
│ 🔧 Function Calling 层 │
│ ↓ 执行工具 │
│ 📦 工具集 │
│ ├── 网页搜索(SearXNG) │
│ ├── 文件读写(MCP Filesystem) │
│ ├── 数据库查询(MCP SQLite) │
│ ├── 日程管理(MCP Calendar) │
│ └── 自定义API(用户编写) │
│ ↓ 结果返回 │
│ 💬 生成最终回答 │
└─────────────────────────────────────────────┘
2. Function Calling 原理与协议标准
2.1 工作流程
Function Calling 的核心思想是:让LLM输出结构化的"工具调用指令",由外部程序执行工具,再把结果喂回LLM。
用户: "深圳今天天气怎么样?"
↓
LLM判断: 需要调用 get_weather(city="深圳")
↓
程序执行: get_weather("深圳") → {temperature: 28, condition: "晴"}
↓
LLM接收结果: 基于{28℃,晴}生成回答
↓
用户收到: "深圳今天28℃,晴天。"
2.2 OpenAI Function Calling 格式(Ollama 兼容)
{
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"}
},
"required": ["city"]
}
}
}
]
}
Ollama 从 0.3.0 版本开始支持 tools 参数,格式与 OpenAI 兼容。
3. 本地模型工具调用能力对比
3.1 支持 Function Calling 的本地模型
| 模型 | 参数量 | 工具调用质量 | 推荐场景 | 拉取命令 |
|---|---|---|---|---|
| Qwen2.5 | 7B/14B/32B | ⭐⭐⭐⭐⭐ | 通用Agent | ollama pull qwen2.5:14b |
| DeepSeek-R1 | 14B/32B/70B | ⭐⭐⭐⭐ | 推理+工具 | ollama pull deepseek-r1:14b |
| Llama 3.2 | 8B/70B | ⭐⭐⭐⭐ | 通用 | ollama pull llama3.2:8b |
| Mistral Nemo | 12B | ⭐⭐⭐ | 轻量Agent | ollama pull mistral-nemo:12b |
| Command-R | 35B | ⭐⭐⭐⭐ | RAG+工具 | ollama pull command-r:35b |
💡 建议:Qwen2.5 14B 的工具调用格式最稳定,推荐作为 Agent 主力模型。
3.2 验证模型工具调用能力
# 用 Ollama API 测试工具调用
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5:14b",
"messages": [{"role": "user", "content": "深圳今天天气怎么样?"}],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取城市天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
}
}
]
}'
如果模型支持工具调用,返回中会包含 "tool_calls" 字段。
4. OpenWebUI 中配置 Function Calling
OpenWebUI 内置了对工具调用的支持,并通过 Functions(函数) 机制允许用户输入自定义工具。
4.1 启用工具调用(确认模型支持)
在 OpenWebUI 设置中:
- Settings → Models:确保选中的模型支持工具调用(Ollama 0.3+)
- Settings → Functions:查看已安装的函数
4.2 编写并安装自定义 Function
OpenWebUI 的 Function 使用 Python 编写,格式如下:
"""
name: get_weather
description: 获取指定城市的当前天气信息。当用户询问天气时调用。
"""
import requests
def get_weather(city: str):
"""
调用 wttr.in 免费天气API
"""
try:
resp = requests.get(f"https://wttr.in/{city}?format=j1", timeout=10)
data = resp.json()
current = data["current_condition"][0]
return {
"city": city,
"temperature": current["temp_C"] + "°C",
"condition": current["weatherDesc"][0]["value"],
"humidity": current["humidity"] + "%"
}
except Exception as e:
return {"error": str(e)}
安装步骤:
- 打开 OpenWebUI → 左下角头像 → Settings
- 点击 Functions → + 创建
- 粘贴以上代码 → 保存
- 在聊天界面中,AI 会自动发现并使用这个工具
5. 实战:编写自定义工具函数
5.1 工具函数编写规范
每个工具函数应遵循以下规范:
"""
name: tool_name
description: 清晰描述工具的用途、何时调用、参数是什么。
好的description能让LLM准确判断何时调用此工具。
"""
def tool_name(param1: str, param2: int = 10):
"""
函数文档字符串:说明参数含义、返回值格式
"""
# 1. 参数校验
if not param1:
return {"error": "param1 is required"}
# 2. 执行操作
result = do_something(param1, param2)
# 3. 返回结构化结果(JSON序列化友好的dict)
return {
"status": "success",
"data": result,
"count": len(result)
}
5.2 实用工具示例:知识库搜索工具
"""
name: search_knowledge_base
description: 在本地知识库中搜索相关信息。当用户询问需要查阅知识库内容时调用。
"""
import requests
def search_knowledge_base(query: str, max_results: int = 5):
"""
调用 OpenWebUI 内置的 RAG 检索接口
(需要 OpenWebUI 已配置知识库)
"""
try:
# 调用 OpenWebUI 内部 RAG API
# 注意:这需要 OpenWebUI 的 Python 环境内有相应上下文
# 实际部署时,建议通过 OpenWebUI 插件机制实现
return {
"query": query,
"results": [],
"note": "需通过OpenWebUI插件机制实现"
}
except Exception as e:
return {"error": str(e)}
6. MCP 协议:连接一切的标准接口
6.1 MCP 是什么?
MCP(Model Context Protocol) 是 Anthropic 于2024年推出的开放标准协议,用于解决 AI 应用与外部工具/数据源之间的连接问题。
核心价值:
- 对工具开发者:只需实现一次 MCP Server,所有支持 MCP 的 AI 应用都能用
- 对 AI 应用:只需支持 MCP Client,就能连接所有 MCP Server
- 对用户:像"插USB设备"一样给 AI 添加新能力
6.2 MCP 架构
┌─────────────────┐ MCP协议 ┌─────────────────┐
│ AI应用 │ ←────────────→ │ MCP Server │
│ (OpenWebUI/ │ 标准JSON-RPC │ (提供工具/数据) │
│ Claude等) │ │ │
└─────────────────┘ └─────────────────┘
6.3 官方 MCP Server 列表
| MCP Server | 功能 | 安装 |
|---|---|---|
| @modelcontextprotocol/server-filesystem | 文件系统读写 | npm install -g @modelcontextprotocol/server-filesystem |
| @modelcontextprotocol/server-brave-search | 网页搜索 | npm install -g @modelcontextprotocol/server-brave-search |
| @modelcontextprotocol/server-sqlite | SQLite数据库 | npm install -g @modelcontextprotocol/server-sqlite |
| @modelcontextprotocol/server-git | Git仓库操作 | npm install -g @modelcontextprotocol/server-git |
| @modelcontextprotocol/server-fetch | 获取URL内容 | npm install -g @modelcontextprotocol/server-fetch |
| @modelcontextprotocol/server-postgres | PostgreSQL | npm install -g @modelcontextprotocol/server-postgres |
7. OpenWebUI + MCP 完整配置
7.1 OpenWebUI 的 MCP 支持现状
截至 2025 年初,OpenWebUI 对 MCP 的支持处于实验阶段,主要通过以下方式实现:
方式一:通过 OpenWebUI Functions 调用 MCP Server
在 Function 中,使用 subprocess 调用 MCP Server 的 stdio 接口:
"""
name: mcp_filesystem
description: 通过MCP协议访问文件系统
"""
import subprocess
import json
def mcp_filesystem(operation: str, path: str, content: str = ""):
"""
调用 MCP filesystem server
"""
# 构建 MCP 请求
request = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "read_file" if operation == "read" else "write_file",
"arguments": {"path": path, "content": content}
}
}
# 通过 stdin 发送给 MCP Server
result = subprocess.run(
["npx", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
input=json.dumps(request),
capture_output=True,
text=True
)
return json.loads(result.stdout)
方式二:等待 OpenWebUI 原生 MCP 支持
OpenWebUI 开发团队已在 roadmap 中规划原生 MCP 支持,未来可直接在 UI 中配置 MCP Server 地址。
7.2 当前推荐方案:用 OpenWebUI Functions 替代 MCP
在 OpenWebUI 原生支持 MCP 之前,直接用 Functions 编写工具函数是最稳定的方案。
8. 实战案例:文件管理 Agent
8.1 目标
让 AI 能:
- 列出指定目录的文件
- 读取文件内容并总结
- 写入新文件
8.2 实现:文件操作工具函数
"""
name: file_manager
description: 管理指定目录下的文件。支持列出文件、读取文件、写入文件。当用户需要操作文件时调用。
"""
import os
import json
# 安全限制:只能访问这些目录
ALLOWED_DIRS = [
"D:/AI_Workspace",
"D:/UserData/Desktop/workspace"
]
def _check_path(path: str) -> bool:
"""检查路径是否在允许范围内"""
return any(os.path.abspath(path).startswith(os.path.abspath(d)) for d in ALLOWED_DIRS)
def list_files(directory: str = "D:/AI_Workspace") -> dict:
"""列出目录下的所有文件"""
if not _check_path(directory):
return {"error": "Path not allowed"}
try:
files = []
for f in os.listdir(directory):
fp = os.path.join(directory, f)
files.append({
"name": f,
"size": os.path.getsize(fp) if os.path.isfile(fp) else 0,
"is_dir": os.path.isdir(fp)
})
return {"directory": directory, "files": files, "count": len(files)}
except Exception as e:
return {"error": str(e)}
def read_file(path: str) -> dict:
"""读取文件内容"""
if not _check_path(path):
return {"error": "Path not allowed"}
try:
with open(path, "r", encoding="utf-8") as f:
content = f.read()
return {"path": path, "content": content, "length": len(content)}
except Exception as e:
return {"error": str(e)}
def write_file(path: str, content: str) -> dict:
"""写入文件(仅允许写入AI_Workspace目录)"""
if not _check_path(path):
return {"error": "Path not allowed"}
try:
with open(path, "w", encoding="utf-8") as f:
f.write(content)
return {"path": path, "status": "success", "bytes": len(content)}
except Exception as e:
return {"error": str(e)}
8.3 使用效果
在 OpenWebUI 中安装上述 Function 后:
用户:帮我看看 D:/AI_Workspace 里有哪些文件?
AI:(调用list_files)→ 有3个文件:note.txt、todo.md、draft.md用户:帮我总结一下 note.txt 的内容
AI:(调用read_file)→ 总结了文件内容
9. 定时任务:让 Agent 自动执行
9.1 方案架构
Windows任务计划程序 / cron
↓ 定时触发
Python脚本(调用Ollama API)
↓ 构造prompt
Ollama(本地模型)
↓ 生成结果
发送到邮箱 / 微信 / 本地通知
9.2 实现:每日工作总结脚本
# D:/AI_Workspace/daily_agent.py
import requests
import json
from datetime import datetime
API_URL = "http://localhost:11434/api/chat"
MODEL = "qwen2.5:14b"
def ask_agent(prompt: str) -> str:
"""调用本地Ollama API"""
payload = {
"model": MODEL,
"messages": [{"role": "user", "content": prompt}],
"stream": False
}
resp = requests.post(API_URL, json=payload, timeout=120)
return resp.json()["message"]["content"]
def main():
today = datetime.now().strftime("%Y-%m-%d")
prompt = f"""
今天是{today}。
请基于你的知识,生成今日工作建议,包括:
1. 今日优先级最高的3件事
2. 需要注意的事项
3. 一句鼓励的话
(500字以内,语气积极)
"""
result = ask_agent(prompt)
# 保存结果
with open(f"D:/AI_Workspace/daily_{today}.txt", "w", encoding="utf-8") as f:
f.write(result)
print("生成完成:")
print(result)
if __name__ == "__main__":
main()
9.3 配置 Windows 任务计划程序
# 创建一个基本任务
# 触发器:每天早上 8:00
# 操作:启动程序
# 程序:python.exe
# 参数:D:\AI_Workspace\daily_agent.py
10. 安全与权限控制
10.1 安全风险分析
| 风险类型 | 描述 | 防护措施 |
|---|---|---|
| 路径遍历 | AI被诱导读取 /etc/passwd 等敏感文件 |
白名单限制允许路径 |
| 命令注入 | 工具函数中使用 os.system 导致代码执行 |
禁止在工具函数中使用shell命令 |
| 无限循环 | AI反复调用工具耗尽资源 | 限制单轮对话最大工具调用次数 |
| 提示词注入 | 外部内容(网页/文档)中包含恶意指令 | 不信任外部输入,隔离工具执行 |
10.2 安全编码规范
"""
安全工具函数模板
"""
import os
import re
# 严格定义允许的操作范围
ALLOWED_DIR = os.path.abspath("D:/AI_Workspace")
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
MAX_CALLS_PER_TURN = 10 # 单轮最大调用次数
def safe_path(path: str) -> str:
"""将路径规范化为绝对路径,并检查安全性"""
abs_path = os.path.abspath(path)
if not abs_path.startswith(ALLOWED_DIR):
raise ValueError(f"Path {path} is not allowed")
return abs_path
def safe_read(path: str) -> dict:
"""安全读取文件"""
try:
path = safe_path(path)
if not os.path.isfile(path):
return {"error": "Not a file"}
if os.path.getsize(path) > MAX_FILE_SIZE:
return {"error": "File too large"}
with open(path, "r", encoding="utf-8") as f:
return {"content": f.read()}
except Exception as e:
return {"error": str(e)}
11. 总结与下一步
11.1 本文回顾
| 章节 | 核心内容 |
|---|---|
| Function Calling 原理 | LLM生成工具调用指令 → 程序执行 → 结果返回LLM |
| 模型选择 | Qwen2.5 14B 工具调用最稳定 |
| OpenWebUI Functions | 用Python编写自定义工具函数 |
| MCP 协议 | 标准化工具接入协议,未来主流方向 |
| 文件管理Agent | 实战案例:让AI读写指定目录 |
| 定时任务 | 用任务计划程序 + Ollama API 实现定时Agent |
| 安全规范 | 路径白名单、禁止shell命令、限制调用次数 |
11.2 系列进度
| 篇目 | 主题 | 状态 |
|---|---|---|
| 第1-7篇 | 基础部署到远程访问 | ✅ |
| 第8篇 | AI Agent + Function Calling | ✅ 新! |
| 第9篇(下篇) | 高性能优化:GPU加速+模型量化 | 🔜 下周更新 |
11.3 下一步可以做什么?
- 接入 Home Assistant:让AI控制智能家居
- 接入企业微信/钉钉:让AI成为企业助手
- 多Agent协作:一个Agent搜索、一个Agent总结、一个Agent发送
- Fine-tuning:用你的数据微调模型,提升工具调用准确率
系列文章导航:
- 第1篇:免费安装本地DeepSeek
- 第2篇:Page Assist浏览器AI插件
- 第3篇:OpenWebUI搭建ChatGPT级界面
- 第4篇:给本地AI加上联网搜索
- 第5篇:搭建RAG知识库
- 第6篇:多模态+语音交互
- 第7篇:手机远程访问本地AI
- 第8篇(本文):AI Agent与Function Calling
- 第9篇:高性能优化(待更新)
💬 互动话题:你最想让AI Agent帮你自动完成什么任务?是文件整理、信息汇总、还是定时提醒?评论区分享你的想法,说不定下一篇就讲你需要的方案!🎉
🏷️ 发布提示:发布时请添加标签「本地AI」「AI Agent」「Function Calling」「MCP协议」「Python」,以提升推荐曝光。
参考资料:
更多推荐

所有评论(0)