这次我们来看 Agent Skills。它不是某个具体模型,而是吴恩达在 2025 年反复强调的智能体开发方法论:把大模型从“能聊天”变成“能干活”。网上很多人把它总结成一句话:Agent = 大模型 + 记忆 + 规划 + 工具调用,而 Agent Skills 就是里面那组可以被复用、组合、独立部署的“工具模块”。
这个主题最值得关注的点有三个:一是它把复杂的大模型应用拆成了标准化技能,像搭积木一样组合;二是它不挑硬件,CPU 也能玩,有显卡推理更快,很适合本地部署试验;三是它直接和代码实战挂钩,可以用 OpenAI 兼容接口、Ollama 或者常见云厂商 API 快速跑通一个带工具调用的 Agent。
这篇文章会从概念讲起,然后给出一套可落地的本地部署流程:先启动一个本地大模型服务,再写一个支持工具调用的 Agent 代码,封装一个“执行 Python 代码”的 Skill,接着测试接口和批量任务,最后补充性能观察、常见问题排查和最佳实践。
1. Agent Skills 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | AI Agent 开发方法论 / 技能封装范式 |
| 来源背景 | 吴恩达在公开课程与博客中强调的 Agent 设计思路,配套多门实战课程 |
| 核心能力 | 工具调用、任务规划、反思修正、记忆管理、多智能体协作 |
| 推荐硬件 | CPU 可入门;有 NVIDIA GPU 推理更快 |
| 显存需求 | 取决于所选本地模型,常见 7B 量化模型约 8GB 以内显存可跑,实际以部署为准 |
| 支持平台 | Windows、Linux、macOS |
| 启动方式 | Python 脚本直接运行、Jupyter Notebook、FastAPI 服务、Ollama 后台服务 |
| 是否支持 API | 支持,可通过 OpenAI 兼容接口或自定义 FastAPI 接口调用 |
| 是否支持批量任务 | 支持,可用脚本循环处理输入目录中的多个文件 |
| 适合场景 | 代码生成后自动执行、文档批量处理、检索问答、报表生成、测试自动化 |
从材料看,Agent Skills 的最大优势不是某个功能的实现,而是它的“可组合性”。你可以把一个 Skill 单独写好,然后在不同 Agent 工作流里复用,不需要每次重新训练模型。
2. Agent Skills 是什么:从提示词到可复用技能
2.1 从 Prompt 到 Agent
传统大模型用法是写一段提示词,模型输出一段文字。这种方式适合问答,但不适合“干活”。因为干活通常需要查数据库、执行代码、调用外部 API、读取文件、定时轮询等能力,而这些是模型本身做不了的。
Agent 的出现就是为了解决这个问题。Agent 是一个有“感知-决策-行动”闭环的系统:它接收用户任务,调用大模型做推理和规划,然后通过 Skill 去执行具体动作,再把执行结果反馈给模型,决定下一步做什么。
这里的关键区别是:Prompt 是一次性输入,Agent 是循环过程;Prompt 是文本模板,Agent 是可运行的程序。
2.2 Agent Skills 与 Function Calling 的关系
Agent Skills 在工程上的核心实现方式之一,就是 Function Calling,也就是工具调用。开发者把每个 Skill 定义成一个函数,同时把这个函数的名称、参数结构的 JSON Schema 提供给大模型。模型生成回复时,不再只是输出文本,而是可以输出一个“调用指令”:我应该调用 execute_python,参数是 某个代码字符串。
这个机制让模型拥有了“外部手脚”。常见的 Agent Skill 包括:
| Skill 名称 | 职责 | 典型用途 |
|---|---|---|
| 代码执行器 | 运行 Python 代码并返回结果 | 数据分析、爬虫、脚本测试 |
| 文档检索器 | 从本地文档库中搜索相关内容 | 知识库问答、合同审查 |
| 数据查询器 | 查询数据库或表格 | 报表生成、业务分析 |
| HTTP 请求器 | 调用外部 API | 天气查询、订单查询、消息发送 |
| 文件操作器 | 读写本地文件 | 批量处理、格式转换 |
| 反思修正器 | 检查上一轮输出并修正错误 | 代码调试、内容审核 |
每一种 Skill 都是一个小模块,可以单独测试,也可以组合使用。
2.3 四种典型设计模式
吴恩达在公开演讲中多次介绍过 Agent 的几种设计模式,这套思路也可以直接套用到 Agent Skills 的工程实现上:
- 直接输出模式:模型一步生成最终结果,适合简单任务。
- 工具调用模式:模型根据用户请求调用一个或多个 Skill,这是 Agent 的核心模式。
- 反思模式:模型先生成结果,再自己检查、指出问题并修正,适合代码生成和写作。
- 规划模式:模型先把大任务拆成子任务,再逐个执行,适合复杂流程。
实际开发时,这几种模式经常混用:先规划,再调用工具,再做一次反思修正。Skill 就是这些模式里的“执行单元”。
3. 适用场景与使用边界
3.1 适合谁用
Agent Skills 适合以下几类人:
- 想给 ChatGPT 类应用加“动手能力”的开发者;
- 需要把内部知识库、数据库、脚本能力接入大模型的工程师;
- 刚接触大模型应用开发、想从提示词工程进阶到 Agent 开发的初学者;
- 需要批量处理文档、代码、数据的运维和测试人员。
3.2 能解决什么问题
最直接的收益是省掉重复劳动。以前你要写一个固定流程脚本,现在可以写一个 Agent Skill,让大模型根据用户输入动态决定要不要调用它。比如“帮我统计数据并画图”这个任务,模型可以先调用数据查询器拿数据,再调用代码执行器画图,最后返回一张图和一个解释文本,全流程不需要人手工切换工具。
3.3 使用边界与合规提醒
- Agent 会随意外呼接口、执行代码,所以在公网环境部署时必须做权限控制,比如限制请求来源、增加 API Key、使用内网隔离。
- 代码执行类 Skill 不要直接运行不可信代码,否则可能造成系统破坏或数据泄露。
- 涉及人脸、声音、版权素材、个人隐私数据时,必须确认数据来源和授权范围。
- Agent 输出结果不代表事实正确,商用前要做人工复核。
4. Agent Skills 本地部署环境准备
4.1 环境清单
开始之前,先确认本机环境:
- 操作系统:Windows 10/11、Ubuntu 20.04+ 或 macOS 12+。
- Python 版本:建议 3.10 或 3.11。
- Node.js:可选,部分 Agent 框架会用到。
- 包管理工具:pip 和 conda 二选一。
- 模型推理服务:推荐 Ollama,也可以使用 vLLM 或 LM Studio。
- GPU 环境:如果使用 NVIDIA 显卡,建议安装新版驱动和 CUDA 工具包;如果不装 GPU,模型会走 CPU,推理速度会慢一些。
4.2 安装 Python 依赖
创建一个项目目录,并在其中创建虚拟环境:
mkdir agent-skills-demo cd agent-skills-demo python -m venv venv # Windows 激活 venv\Scripts\activate # Linux / macOS 激活 source venv/bin/activate安装核心依赖:
pip install openai ollama fastapi uvicorn ipython requests这里解释一下各个依赖的用途:
openai:Python SDK,用于调用 OpenAI 兼容接口,包括 Ollama 的本地接口。ollama:Python 客户端,也可以直接调用 Ollama 的本地服务。fastapi和uvicorn:用来把 Skill 封装成 HTTP 服务。jupyter:用来做实验调试,方便看到每一步的中间结果。
4.3 磁盘与端口规划
本地大模型文件通常有几个 GB,建议预留至少 30GB 磁盘空间,避免下载到一半空间不足。Ollama 默认端口是11434,FastAPI 服务可以自定义端口,比如8000。如果端口被占用,启动时会报错,后面常见问题部分会展开说。
5. 把本地大模型跑起来:Ollama 快速启动
5.1 安装并拉起服务
Ollama 是当前最简单的本地大模型运行方式,安装后直接在终端执行:
ollama pull qwen2.5:7b ollama servepull会下载模型文件,不同标签和版本所需空间不同,具体以 Ollama 官方仓库为准。serve启动后,Ollama 会在本地提供 API 服务。
5.2 用 curl 验证接口
服务启动后,用 curl 发一个测试请求:
curl http://127.0.0.1:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5:7b", "messages": [ {"role": "user", "content": "你好,请做一个自我介绍"} ] }'注意,这里api_key可以随便填,因为 Ollama 本地服务默认不做鉴权。如果接口能正常返回结果,说明本地模型服务已经跑通。
5.3 没有 GPU 怎么办
没有 GPU 时,Ollama 会默认使用 CPU 推理,可以工作,但速度会慢。建议优先选择 1.5B 或 3B 的小模型做功能验证,跑通后再切换更大的模型。显存占用需要结合量化方式和上下文长度判断,通常来说模型越小、上下文越短,占用越低。
6. 代码实战:写一个支持工具调用的 Agent Skill
6.1 定义 Skill 函数
这里我们做一个实际可跑的 Skill:execute_python,它负责接收一段 Python 代码并执行,把标准输出和返回值返回给 Agent。
import io import sys import contextlib def execute_python(code: str) -> str: """执行一段 Python 代码,返回标准输出和返回值。""" output = io.StringIO() error = io.StringIO() result = None try: with contextlib.redirect_stdout(output), contextlib.redirect_stderr(error): exec(code, {"__name__": "__main__"}, {}) except Exception as e: error.write(f"执行出错: {e}") final_result = "" if output.getvalue(): final_result += f"标准输出:\n{output.getvalue()}\n" if error.getvalue(): final_result += f"错误信息:\n{error.getvalue()}\n" return final_result.strip() or "无输出"这里使用了contextlib.redirect_stdout和redirect_stderr来捕获运行结果。实际生产环境里如果要执行不可信代码,必须放到 Docker 或沙箱容器中,不能直接在宿主机上跑。
6.2 组装 Tool Schema
为了让大模型知道这个 Skill 的存在,需要按照 Function Calling 的格式,把这个函数描述成为 tool:
tools = [ { "type": "function", "function": { "name": "execute_python", "description": "执行一段 Python 代码,适合做计算、数据处理、文件读取等操作。", "parameters": { "type": "object", "properties": { "code": { "type": "string", "description": "要执行的 Python 代码" } }, "required": ["code"] } } } ]这段 JSON 是模型和程序之间的“接口契约”。模型看到这段描述后,如果判断任务需要执行代码,就会返回一个 tool_calls 调用请求。
6.3 实现 Agent 主循环
现在编写核心的 Agent 消息循环。基本流程是:
- 把用户消息加入 messages。
- 请求大模型,传入 tools。
- 如果模型返回 tool_calls,就执行对应 Skill,把结果加入 messages。
- 再次请求大模型,直到模型不再返回 tool_calls。
from openai import OpenAI client = OpenAI( base_url="http://127.0.0.1:11434/v1", api_key="ollama", ) def run_agent(user_prompt: str, max_iterations: int = 5) -> str: messages = [{"role": "user", "content": user_prompt}] for step in range(max_iterations): response = client.chat.completions.create( model="qwen2.5:7b", messages=messages, tools=tools, temperature=0.2, ) message = response.choices[0].message # 如果没有工具调用请求,说明模型已经给出最终答案 if not message.tool_calls: return message.content # 把模型发出的工具调用请求加入历史 messages.append(message.model_dump()) # 逐个执行工具调用 for tool_call in message.tool_calls: if tool_call.function.name == "execute_python": args = tool_call.function.arguments # 注意:arguments 是 JSON 字符串,需要解析 import json code = json.loads(args)["code"] tool_result = execute_python(code) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": tool_result, }) return "达到最大迭代次数,任务结束。"这个主循环是最小可用的 Agent 原型。max_iterations很重要,不加限制的话,模型可能会陷入“执行-出错-再执行”的死循环。
6.4 运行效果验证
写一个 test 脚本调用上面的run_agent:
if __name__ == "__main__": result = run_agent("请计算 1 加到 100 的结果,并给出代码。") print(result)跑起来之后,你会看到 Agent 的输出。如果配置正确,本地模型会先返回一个 tool_calls 调用请求,主循环执行代码后把结果返回给模型,模型再基于执行结果给出最终回答。判断成功的标准是输出里包含“5050”这个结果,而不只是模型“猜”出一个答案。
如果失败,最常见的情况是本地模型不支持工具调用,或者 Qwen 模型在 Ollama 中的工具调用支持不完整。可以换一个更大的模型,或者把 prompt 改成“请用少量代码计算 1 到 100 的和”,让模型直接输出代码,再手动执行。
7. 接口 API 与批量任务实战
7.1 把 Skill 封装成 FastAPI 服务
除了在 Python 脚本里直接调用,还可以把 Skill 封装成 HTTP 接口,方便给前端、定时任务或第三方工具调用。
先创建一个skill_server.py文件:
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class ExecuteRequest(BaseModel): code: str @app.post("/v1/skills/execute_python") def execute_python_api(req: ExecuteRequest): result = execute_python(req.code) return { "status": "ok", "output": result } if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)启动服务:
uvicorn skill_server:app --host 127.0.0.1 --port 8000然后用 curl 测试接口:
curl -X POST http://127.0.0.1:8000/v1/skills/execute_python \ -H "Content-Type: application/json" \ -d '{"code": "print(21 * 2)"}'如果返回结果里有42,说明接口已经跑通。这个接口可以被外部 Agent 编排系统调用,也可以在前端页面直接请求。
7.2 批量任务设计
批量任务是 Agent Skills 比较实用的场景。这里演示一个最常用的批量处理流程:遍历输入目录中的所有.txt文件,让 Agent 对每个文件做摘录总结,然后保存到输出目录。
import os from pathlib import Path INPUT_DIR = "./inputs" OUTPUT_DIR = "./outputs" os.makedirs(OUTPUT_DIR, exist_ok=True) def summarize_text(text: str) -> str: prompt = f"请用 3 句话总结下面的文本:\n\n{text}" return run_agent(prompt) for file_path in Path(INPUT_DIR).glob("*.txt"): text = file_path.read_text(encoding="utf-8") summary = summarize_text(text) output_file = Path(OUTPUT_DIR) / f"{file_path.stem}_summary.txt" output_file.write_text(summary, encoding="utf-8") print(f"已完成: {file_path.name}")批量任务有几个注意点:
- 给每个文件加上超时控制,避免某个文件耗时过长导致整个脚本卡住。
- 记录日志和已处理列表,中途失败后可以跳过已完成文件,继续重跑。
- 控制并发数,不要一次性开几十个线程请求本地模型,否则显存或 CPU 会被打满。
7.3 增加失败重试
在批量场景下,网络抖动或模型输出异常都可能出现。一个简单可靠的模式是加重试装饰器:
import time from functools import wraps def retry(max_retries: int = 3, delay: float = 2.0): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): for attempt in range(max_retries): try: return func(*args, **kwargs) except Exception as e: print(f"第 {attempt + 1} 次调用失败: {e}") if attempt == max_retries - 1: raise time.sleep(delay) return wrapper return decorator @retry(max_retries=3, delay=1.0) def call_agent_once(prompt: str) -> str: return run_agent(prompt)不要一开始就把重试次数设得很大,否则批量任务会卡在坏数据上。推荐先重试 2 到 3 次,失败的任务单独记录到一个failed.txt清单,最后统一排查。
8. 资源占用与性能观察
8.1 观察工具
本地跑 Agent 时,重点观察两个指标:内存/显存占用和单次请求耗时。
- 终端里可以用
nvidia-smi查看 GPU 显存和利用率;如果没有 GPU,用系统任务管理器看内存和 CPU。 - Ollama 提供
ollama ps命令,可以直接看到当前加载了哪些模型、显存占用情况。 - 在代码里可以给请求加计时,把每次调用的耗时记录下来。
ollama ps如果发现显存占用一直很高,可以卸载不用的模型,或者在 Ollama 配置里限制并发请求数。
8.2 影响性能的因素
从实战经验看,下面几个因素对性能影响最大:
- 模型大小:7B 模型比 1.5B 模型慢很多,显存占用也更高。
- 上下文长度:messages 里历史消息越长,推理越慢。
- 工具调用轮数:每次函数执行后都要再请求一次模型,环节越多耗时越长。
- 输出长度:
max_tokens越大,单次生成时间越长。 - 并发数:多个线程同时请求时,如果显存不足,会出现排队或报错。
建议第一次先用小模型、短上下文、并发数为 1 的场景跑通整个链路,再逐步增加复杂度。
9. Agent Skills 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| Ollama 服务启动后接口无法访问 | 端口被占用或服务未启动 | 查看终端日志,执行 `netstat -ano | findstr 11434` |
| 模型下载慢或失败 | 网络问题或模型文件过大 | 检查网络连通性,查看磁盘剩余空间 | 先下载小模型如qwen2.5:1.5b,或检查镜像源 |
| Agent 不返回工具调用 | 本地模型不支持 Function Calling | 打印 model 层原始返回,查看tool_calls字段 | 换用更大模型,或降低模型版本要求 |
| 工具调用参数解析失败 | arguments不是合法 JSON | 打印tool_call.function.arguments原生内容 | 使用json.loads前先做字符串清洗 |
| Agent 陷入无限循环 | 缺少最大迭代限制 | 检查主循环里max_iterations参数 | 增加迭代上限,超限后返回当前结果 |
| 中文输出被截断 | max_tokens设置过小 | 检查返回的finish_reason是否为length | 调大max_tokens |
| 批量任务中途卡住 | 单条数据超时或模型响应慢 | 在调用处加日志,记录当前处理文件 | 增加超时控制,把失败任务单独记录 |
| 服务端口一直报占用错误 | 上一次进程没有正常退出 | 查看进程列表,确认端口对应的 PID | 杀掉残留进程或换个新端口 |
10. 最佳实践与安全边界
10.1 工程规范
第一次上手工装 Agent Skills 的时候,建议先建立一套最小可运行模板,统一管理模型配置和 Skill 注册表。比如可以在一个skills.py文件里维护所有 Skill 函数和对应的工具描述,不要散落在不同 Notebook 里,这样后面加新 Skill 只需要改一处。
批量任务要加日志和失败重试,不要让脚本“静默失败”。每个任务处理前打印输入文件路径、开始时间和结束时间;失败时把异常信息写入单独日志文件。否则大批量处理完成后,很难判断哪些文件成功、哪些被跳过了。
10.2 权限与风险控制
Agent Skill 有执行能力,所以权限控制不能偷懒:
- 代码执行 Skill 必须做沙箱隔离,至少使用 Docker 容器运行,避免在宿主机上直接执行任意代码。
- HTTP 请求 Skill 要限制目标地址,不能允许模型任意访问内网 IP,否则可能被用来做内网探测。
- API 服务不能直接暴露到公网,至少要加 API Key 鉴权,并限制来源 IP。
- 工具调用的执行结果不能无条件信任,Agent 的“我认为执行成功”不等于真的成功,关键步骤要人工确认。
10.3 数据与版权合规
如果 Agent 要处理文档、图像、音视频等素材,必须先确认素材来源和授权情况。涉及人脸图像、声音克隆、版权文字时,要确保已经获得合法授权,不能随便用抓取的数据做训练或自动化处理。
11. 总结与下一步建议
Agent Skills 最值得尝试的点,是它把大模型从“文本生成器”变成了“任务执行器”。你不需要重新训练模型,只需要把现有能力封装成标准化的 Skill,再通过工具调用机制组合起来,就可以完成很多以前需要写大量脚本才能完成的自动化任务。
上手第一步先别追求复杂,优先验证一件事:本地模型能不能在对话中返回tool_calls。这一步跑通后,后面所有东西都顺了。最容易踩的坑也在这里:很多小模型虽然能聊天,但不一定完整支持 Function Calling,遇到这种情况不要死磕,直接换支持工具调用的模型或版本。
后续可以继续扩展的方向包括:给 Agent 加短期记忆,让它在多个任务间记住上下文;把多个 Skill 编排成完整工作流,实现“规划-执行-反思”的闭环;再把 Skill 服务化部署到内网,接入定时任务或消息队列,做成真正可用的自动化系统。
建议先照着文章里的最小原型跑一遍:Ollama 启动、Agent 主循环、execute_python 工具调用、批量处理脚本。跑通之后,再根据自己的实际场景加业务 Skill,效果比直接啃概念要好得多。