这一波 AI 代理的热度确实高,但很多人并没有把概念落到工程上。尤其是看到“WebMCP”“AI 代理助手加本地模型”这类关键词时,容易误以为又是某个神秘工具或暴利项目。实际上,WebMCP 思路的技术内核非常朴素:让代理能理解网页端的上下文、能调用 Web 工具、能连接本地模型,然后把自动化任务变成可复用、可交付、可定价的服务。本文围绕这套思路,完整拆解 AI 代理的基本原理、WebMCP 的概念边界、本地模型与代理助手的组合开发,并给出一套可运行的工程示例,适合想入门 AI 代理开发或者正在做自动化工具落地的开发者。
1. WebMCP 与 AI 代理初印象:从概念说起
1.1 什么是 AI 代理
AI 代理(AI Agent)不是一个新的数学模型,而是一种软件架构。传统的程序是“输入 -> 固定逻辑 -> 输出”,AI 代理则是“输入 -> 大模型推理 -> 选择工具 -> 执行工具 -> 再次推理 -> 输出”。它的核心不是模型本身,而是模型外围那一层“调度系统”。
一个最简单的 AI 代理由三部分组成:
- 大语言模型(LLM):负责理解意图、生成计划和判断结果。
- 工具集合(Tools):模型可以调用的外部能力,比如搜索引擎、数据库、计算器、HTTP 接口。
- 运行循环(Loop):模型判断是否调用工具、调用哪个工具、得到结果后如何续写。
从工程实现来看,AI 代理的本质就是一段可以动态决定“下一步做什么”的程序。传统代码的控制流是写死的,代理的控制流是模型根据上下文动态产生的。这让它可以处理一些边界模糊、步骤不固定的任务,下面是它在业务中的常见形态。
- 自动化资料整理:从一批网页或文档中提取结构化信息。
- 智能客服:结合本地知识库和企业 API 回答用户问题。
- 数据分析助手:根据自然语言生成 SQL,查询后返回图表或结论。
- 内容生产流水线:选题、检索、生成初稿、人工审核。
这些场景有一个共同点:大量重复、规则相对明确、但每次输入的细节都不同。这类任务正是 AI 代理最适合介入的区间。
1.2 MCP 与 WebMCP 的关系
MCP 的全称是 Model Context Protocol,即模型上下文协议。它解决的核心问题是:每个 AI 应用都接一套独立工具协议,导致可移植性很差。MCP 试图用一套统一协议来描述“工具、资源、提示词”,让模型应用与外部工具解耦。
可以把 MCP 理解成“AI 世界的 USB 接口”。外部工具只要实现统一的 MCP 协议,任何支持 MCP 的客户端都能直接调用。
WebMCP 不是官方规范名称,而是社区对“Web 能力 + MCP 协议”这一组合的通俗称呼。它通常包含下面几层含义:
- 在 Web 服务端实现 MCP Server,让网络接口、浏览器工具、网页信息以标准工具形式暴露给代理。
- 在浏览器扩展或前端页面中集成代理能力,让用户直接和网页数据交互。
- 把 HTTP API、RSS、搜索引擎、网页抓取等资源封装成 MCP 风格的资源配置。
所以,与其把 WebMCP 当成一个神秘工具,不如把它理解为一种设计思路:用统一协议把 Web 资源接入到代理应用中。这样,同一个代理既能对接本地模型,也能对接 Web 工具,扩展性和可维护性都会好很多。
1.3 “让 AI 代理赚钱”到底赚在哪
“让 AI 代理赚钱”这句话容易引起误解。这里不讨论灰色流量或黑产脚本,只讨论合法、可交付的技术服务价值。AI 代理的商业价值主要体现在三个方面。
- 节省人力成本:替代重复的检索、整理、录入工作。
- 提升响应速度:7x24 小时自动化响应,无需等待人工处理。
- 形成可复用产品:把代理能力封装成工具包、服务或订阅产品,按次或按月收费。
真正能持久赚钱的不是“跑一个代理脚本”,而是把代理工程化,交付给企业或个人用户使用。这意味着要有稳定的任务调度、异常处理、日志记录、权限控制和数据隔离能力。本文后续内容,正是围绕如何把这些工程化能力落下来。
2. 本地模型 + AI 代理助手:技术路线与合规边界
2.1 选择本地模型方案
“ai 代理助手加本地模型”是目前很热门的一种组合。相比直接调用云端大模型 API,本地模型有三个不可替代的价值:
- 数据不出内网:敏感业务数据、私有文档不需要发送到外部平台,降低数据泄露风险。
- 可离线运行:断网环境也能提供服务。
- 成本可预估:没有按 token 计费,部署一次运行成本相对固定。
本地模型方案大致分两类:
| 方案 | 配置要求 | 优点 | 不足 |
|---|---|---|---|
| 本地推理框架(Ollama、vLLM、llama.cpp) | 需要 GPU 或高内存 | 部署简单、社区模型多 | 显存受限,模型大小受硬件影响 |
| 云厂商私有化部署 | 独享 GPU 实例 | 性能强、可横向扩展 | 费用较高,仍需网络访问 |
对个人开发者和中小团队来说,Ollama + 开源模型(如 Qwen、Llama 系列)是最快的验证路径。它提供了类似 Docker 的模型管理体验,一条命令拉取模型,一条命令启动服务,非常适合做代理开发的原型验证。
2.2 合法授权与数据安全红线
写代理工具时,最容易忽略的是边界问题。这部分必须提前想清楚,否则项目做得再完善也会翻车。
- 网页抓取:只能访问你有权访问的站点,遵守目标站点的 robots 协议和访问频率限制,不得绕过登录、验证码,不得抓取用户隐私数据。
- 数据使用:如果代理中涉及企业数据,要明确数据来源、授权链路和脱敏方案,不能越权读取其他系统数据。
- 内容生成:AI 生成内容不能用于虚假宣传、恶意批量注册、钓鱼欺诈等违规场景。
- 权限最小化:代理调用工具时,只申请执行任务所必需的最小权限,运行账号不使用管理员权限。
这些不是空话,而是生产环境能否存活的前提。技术能力决定项目上线速度,合规边界决定项目能走多远。
3. 环境准备与项目骨架
3.1 环境与版本说明
本文示例使用 Python 开发,因为 Python 在 AI 工具链和脚本编排上有天然优势。具体版本如下:
- 操作系统:Ubuntu 22.04 / macOS / Windows 均可,以下命令以 Linux/macOS 为例。
- Python:3.10 及以上。
- Ollama:0.3 及以上,用于拉起本地大模型服务。
- 依赖库:requests、FastAPI、uvicorn,用于接口封装和 HTTP 服务。
版本不必完全照搬,重点是一套思路。如果你的项目中已有其他依赖,请注意统一 Python 版本和虚拟环境。
3.2 初始化项目结构
先创建一个清晰的项目目录。实战项目推荐按功能分层,不要把所有代码塞进一个文件。
ai-agent-project/ ├── main.py # 启动入口,用于演示代理助手 ├── agent/ │ ├── __init__.py │ ├── loop.py # 代理运行循环 │ ├── tools.py # 工具函数集合 │ ├── llm.py # 本地模型调用封装 │ └── config.py # 配置项 ├── web/ │ ├── __init__.py │ └── server.py # FastAPI 服务,暴露 WebMCP 风格接口 ├── data/ # 数据文件目录 ├── logs/ # 日志目录 ├── requirements.txt └── .env.example # 环境变量示例在真正开始写代码之前,先把虚拟环境建好,并安装依赖:
python3 -m venv .venv source .venv/bin/activate pip install requests fastapi uvicorn python-dotenv这里把依赖写进 requirements.txt:
requests==2.31.0 fastapi==0.110.0 uvicorn==0.29.0 python-dotenv==1.0.1依赖版本可以根据你的实际环境调整,重点是通过虚拟环境隔离项目依赖,避免污染系统 Python。
4. 搭建本地模型服务
4.1 安装 Ollama
Ollama 是目前安装和运行本地模型最顺手的工具之一。它会自动处理模型权重下载、推理服务启动等繁琐步骤。
安装命令如下:
curl -fsSL https://ollama.com/install.sh | sh如果你使用 macOS,也可以直接去官网下载安装包。安装完成后,先确认服务是否正常运行:
ollama --version ollama serveollama serve会在本地启动服务,默认监听http://localhost:11434。这个地址就是后续代理需要对接的模型接口。
4.2 拉取模型并验证接口
拉取一个适合中文任务的通用模型。以 Qwen2.5 7B 为例:
ollama pull qwen2.5:7b模型下载需要一些时间,取决于网络环境。拉取完成后,可以先用命令行交互方式测试:
ollama run qwen2.5:7b "用一句话介绍什么是AI代理"如果输出正常,说明模型可用。接下来验证 HTTP 接口。Ollama 兼容一个简洁的/api/chat接口,可以直接用 requests 调用:
# 文件路径:agent/llm.py import requests import json OLLAMA_URL = "http://localhost:11434/api/chat" def chat(messages, model="qwen2.5:7b", temperature=0.2): """调用本地模型的 chat 接口""" payload = { "model": model, "messages": messages, "stream": False, "options": { "temperature": temperature } } resp = requests.post(OLLAMA_URL, json=payload, timeout=120) resp.raise_for_status() data = resp.json() return data["message"]["content"]这段代码做了三件事:
- 把对话消息列表发送给 Ollama。
- 关闭流式输出,便于在代理循环里串行处理。
- 从响应中取出模型生成的文本内容。
这里需要留意的是,timeout设置得比较大,因为本地模型推理在无 GPU 时可能较慢。如果请求超时,后续排错时要优先检查模型是否已加载、硬件配置是否足够。
5. 编写 AI 代理助手核心代码
5.1 注册工具函数
代理的价值不在于聊天,而在于工具调用。为了让模型能够“使用工具”,我们需要做两件事:
- 在系统提示词里告诉模型有哪几个工具可以调用。
- 在运行时解析模型的工具调用意图,并执行对应函数。
先写一个简单的工具函数,并注册到工具表中。工具可以是一个查天气的 HTTP 接口:
# 文件路径:agent/tools.py import requests import json def get_weather(city: str) -> str: """通过公开天气接口查询城市天气,仅供技术演示""" try: url = f"https://wttr.in/{city}?format=j1" resp = requests.get(url, timeout=10) resp.raise_for_status() data = resp.json() current = data["current_condition"][0] return json.dumps({ "city": city, "temp": current["temp_C"], "weather": current["weatherDesc"][0]["value"] }, ensure_ascii=False) except Exception as e: return f"查询天气失败:{str(e)}" # 工具注册表:key 是工具名,value 是 (描述, 函数) TOOLS = { "get_weather": ( "查询指定城市的实时天气。参数:city 城市名", get_weather ) }这里用了最简单的方式描述工具。工具注册表的优点是扩展方便:以后新增工具,只需要在TOOLS字典里加一项即可。
5.2 构造代理循环
代理循环的核心思路是这样的:
- 把用户问题、系统提示词、工具描述合并成消息列表。
- 让模型判断是否需要调用工具。
- 如果模型返回工具调用指令,就执行对应函数,把结果追加到消息列表。
- 让模型基于工具结果生成最终回答。
为了让模型按照固定格式返回“调用哪个工具、传什么参数”,我们在系统提示词里规定一个简单的 JSON 协议:
# 文件路径:agent/loop.py import json import re from agent.llm import chat from agent.tools import TOOLS SYSTEM_PROMPT = """ 你是一个智能助手代理,你可以使用以下工具: {tools_description} 如果需要使用工具,请只输出一个 JSON 对象,格式如下: <tool_call> {"tool": "工具名", "params": {"参数名": "参数值"}} </tool_call> 如果不需要使用工具,直接输出回答。 """.strip() def build_tools_description(): desc = [] for name, (description, _) in TOOLS.items(): desc.append(f"- {name}: {description}") return "\n".join(desc) def extract_tool_call(text): """从模型输出中提取工具调用 JSON""" pattern = r"<tool_call>\s*(\{.*?\})\s*</tool_call>" match = re.search(pattern, text, re.DOTALL) if not match: return None try: return json.loads(match.group(1)) except json.JSONDecodeError: return None def run_agent(user_input, max_steps=3): messages = [ {"role": "system", "content": SYSTEM_PROMPT.format( tools_description=build_tools_description() )}, {"role": "user", "content": user_input} ] for _ in range(max_steps): raw_output = chat(messages) tool_call = extract_tool_call(raw_output) if tool_call is None: return raw_output tool_name = tool_call["tool"] params = tool_call.get("params", {}) if tool_name not in TOOLS: messages.append({"role": "user", "content": f"工具 {tool_name} 不存在,请重新选择"}) continue _, func = TOOLS[tool_name] result = func(**params) messages.append({"role": "user", "content": f"工具调用结果:{result}"}) return "已达到最大工具调用次数,请简化问题后重试"这段代码的关键点:
max_steps限制循环次数,防止模型无限调用工具。- 工具结果通过 user 消息返回给模型,这是最简单也最容易控制的方法。
- 如果你要对接更严格的标准工具协议,可以用 MCP 的官方 SDK,但“模型输出工具意图 -> 执行 -> 回填结果”这个循环本质不变。
在main.py里可以这样测试:
# 文件路径:main.py from agent.loop import run_agent if __name__ == "__main__": while True: user_input = input("请输入你的问题(输入 exit 退出):") if user_input.strip().lower() == "exit": break response = run_agent(user_input) print("代理回答:", response)运行:
python main.py输入“北京今天热不热”,模型如果判断需要查天气,就会输出工具调用标签,然后代理循环执行get_weather("北京"),把天气结果回填给模型,最终输出自然语言回答。
5.3 接入 WebMCP 式工具调用
上面每一步都是手动注册工具,但生产环境里工具可能是大量 Web API、数据库接口和搜索能力。WebMCP 思路的落地点,就是用统一的 HTTP 接口管理这些资源。
我们可以用 FastAPI 做一个轻量的“工具注册中心”,把上面的本地工具暴露成 REST API,同时保留一个工具描述接口:
# 文件路径:web/server.py from fastapi import FastAPI from agent.tools import TOOLS, get_weather from pydantic import BaseModel app = FastAPI(title="WebMCP Style Agent Service") class ToolRequest(BaseModel): tool: str params: dict = {} @app.get("/tools") def list_tools(): """返回所有可用工具及其描述""" return { "tools": [ {"name": name, "description": desc} for name, (desc, _) in TOOLS.items() ] } @app.post("/tools/call") def call_tool(req: ToolRequest): """执行工具调用""" if req.tool not in TOOLS: return {"error": f"工具 {req.tool} 不存在"} _, func = TOOLS[req.tool] result = func(**req.params) return {"tool": req.tool, "result": result} @app.post("/chat") def chat_with_agent(prompt: str): """代理对话接口""" from agent.loop import run_agent response = run_agent(prompt) return {"response": response}启动服务:
uvicorn web.server:app --host 0.0.0.0 --port 8000通过统一 HTTP 接口暴露工具后,AI 代理的调用方就不再限于本地 Python 脚本。前端页面、手机应用、其他后端服务都可以通过 POST 请求调用代理能力,这就是“Web + 工具协议”组合在实际工程中的意义。
6. 实战:一个可落地的“自动资料整理代理”
6.1 需求与流程设计
为了让上面的代理真正产生业务价值,我们做一个“自动资料整理代理”。需求如下:
- 用户给出一批 URL 列表和整理要求。
- 代理逐个访问网页,提取标题、正文摘要和关键词。
- 把结果输出为结构化的 JSON 文件。
这个需求的每一步都可以由代理调度完成:
用户输入 URL 列表 | v 代理解析任务,拆分子步骤 | v 对每个 URL:抓网页 -> 清洗文本 -> 提取摘要 -> 提取关键词 | v 汇总结果 -> 写入 JSON 文件需要说明的是,网页抓取必须遵守目标网站的访问权限。本文示例只抓取自己有权访问、且允许爬取的页面,实际使用时请务必确认。
6.2 代码实现
新增一个fetch_webpage工具,它根据 URL 拉取网页并提取正文文本:
# 文件路径:agent/tools.py(追加 import) import re def fetch_webpage(url: str) -> str: """获取网页文本内容,只做基础 HTML 清洗""" try: resp = requests.get(url, timeout=10, headers={ "User-Agent": "Mozilla/5.0 (compatible; AgentDemo/1.0)" }) resp.raise_for_status() resp.encoding = resp.apparent_encoding html = resp.text # 去掉 script 和 style 内容 html = re.sub(r"<(script|style).*?</\\1>", "", html, flags=re.DOTALL) # 去掉 HTML 标签 text = re.sub(r"<[^>]+>", "", html) # 压缩空白 text = re.sub(r"\\s+", " ", text).strip() return text[:2000] except Exception as e: return f"抓取失败:{str(e)}"然后把新工具注册进TOOLS:
TOOLS = { "get_weather": ( "查询指定城市的实时天气。参数:city 城市名", get_weather ), "fetch_webpage": ( "获取指定URL的网页文本内容。参数:url 网页地址", fetch_webpage ) }资料整理代理的入口脚本:
# 文件路径:agent/collector.py import json from agent.loop import run_agent from agent.tools import fetch_webpage URLS = [ "https://example.com/page1", "https://example.com/page2", ] def collect_and_summary(urls): results = [] for url in urls: print(f"正在处理:{url}") page_text = fetch_webpage(url) prompt = f""" 请根据以下网页文本,提取资料信息。 网页地址:{url} 网页内容:{page_text[:1500]} 输出格式如下: {{ "url": "{url}", "title": "标题", "summary": "80字以内摘要", "keywords": ["关键词1", "关键词2"] }} """ output = run_agent(prompt, max_steps=2) results.append({"url": url, "model_output": output}) with open("data/output.json", "w", encoding="utf-8") as f: json.dump(results, f, ensure_ascii=False, indent=2) print("结果已写入 data/output.json") if __name__ == "__main__": collect_and_summary(URLS)6.3 运行与预期输出
执行:
mkdir -p data python -m agent.collector处理过程中,你会看到代理先抓取网页文本,再根据提示词返回结构化的 JSON。最终data/output.json的内容大致如下:
[ { "url": "https://example.com/page1", "model_output": "{\n \"url\": \"https://example.com/page1\",\n \"title\": \"示例页面\",\n \"summary\": \"这是一个用于演示的网页。\",\n \"keywords\": [\"示例\", \"演示\"]\n}" } ]这个结果虽然简单,但已经具备真实业务雏形。如果把它改造为定时任务、加入更多信息源,就可以变成一个企业级的“竞品情报整理工具”或“行业资料聚合工具”。
7. 工程化:从实验脚本到可交付任务
7.1 任务队列与调度
脚本能跑通只是第一步。要作为可交付服务,必须处理任务排队和失败重试的问题。最简单的做法是用 Redis 做任务队列,消费者从队列取任务,执行成功则写入结果库,失败则记录并重试。
一个基础的任务数据结构如下:
{ "task_id": "uuid", "type": "collect", "params": { "urls": ["https://example.com/page1"] }, "status": "pending", "retry_count": 0, "created_at": "2025-01-01T10:00:00" }调度逻辑:
- 生产者:接收用户请求,生成
task写入 Redis。 - 消费者:从 Redis 取出
pending任务,调用代理执行。 - 结果处理:成功则更新状态为
done,失败则根据重试次数决定是否重新入队。
这里不强制引入复杂框架。先保证有一个简单的任务状态流转,后续再按需扩展。
7.2 日志与可观测性
代理的执行链路长,一个问题往往经过“用户输入 -> 模型判断 -> 工具调用 -> 结果回填”多个环节,没有日志几乎无法排错。建议至少记录以下信息:
- 每次用户输入的原始内容。
- 模型每轮输出的原始内容。
- 工具调用的名称、参数、耗时、返回结果。
- 整个会话的 token 估算和耗时。
- 异常堆栈。
Python 端可以使用标准库logging,把日志分别输出到文件和终端:
import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s - %(message)s", handlers=[ logging.FileHandler("logs/agent.log", encoding="utf-8"), logging.StreamHandler() ] ) logger = logging.getLogger("agent")7.3 部署方式简单对比
如果只是个人验证工具,可以直接用uvicorn跑在本地或一台云服务器上。如果面向团队或客户交付,建议按以下方式分层:
| 层级 | 推荐方案 | 说明 |
|---|---|---|
| 模型服务 | Ollama 或 vLLM,独立进程 | 与业务服务分离,便于单独扩容 |
| 业务服务 | FastAPI + Gunicorn/Uvicorn | 对外提供 HTTP 接口 |
| 任务队列 | Redis + Celery 或 RQ | 异步处理耗时任务 |
| 日志与监控 | Loki/Grafana 或云日志服务 | 集中查看调用链路 |
部署时的原则是“代理逻辑与模型服务解耦”。模型服务只负责推理,不耦合业务;业务服务通过 HTTP 调用模型服务。这样后续更换模型、扩容推理资源都更灵活。
8. 常见问题与排查思路
8.1 本地模型返回空内容或报错
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 请求超时 | 模型未加载或硬件性能不足 | 检查ollama ps确认模型已加载;使用 GPU 或更小模型 |
| 返回 500 | Ollama 服务未启动 | 执行ollama serve或重启服务 |
| 输出乱码 | 模型不支持该语言 | 切换为更擅长中文的模型,如 qwen2.5 |
| 代理循环一直调用工具 | 工具描述不够明确 | 在工具描述中补充参数说明和输出格式 |
8.2 工具调用结果不符合预期
当模型输出的 JSON 解析失败时,可以先用最简单的方式修复:在系统提示词中给出明确的示例。模型对示例的学习能力比抽象描述强很多。
比如:
如果需要查询天气,请输出: <tool_call> {"tool": "get_weather", "params": {"city": "北京"}} </tool_call>如果仍然失败,可以在extract_tool_call中用json.dumps重新序列化参数,确保传入工具函数时是字符串类型。
8.3 网页抓取被拒绝或返回反爬页面
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 403 Forbidden | 服务器识别出非浏览器请求 | 设置完整 User-Agent 和常用请求头 |
| 返回空白页 | 页面通过 JS 动态渲染 | 改用浏览器自动化工具或找数据接口 |
| 访问频率被限制 | 请求频率过高 | 增加延迟,控制并发,遵守目标站点规则 |
如果目标站点明确禁止爬取,请放弃该数据源或改用官方 API。技术手段不能突破权限边界。
9. 最佳实践与工程建议
9.1 工具设计要小而专
每个工具函数只做一件事,参数尽量少。工具描述要包含:作用、参数类型、返回值格式、失败情况。大型工具函数会让模型“不知道该传什么参数”,反而降低成功率。
例如,查询天气和查询空气质量是两个数据源,不应该封装成一个含糊的get_weather_info工具,而是拆成get_weather和get_air_quality,由模型自主选择。
9.2 提示词要与工具解耦
不要把工具逻辑写死在系统提示词中。更好的做法是,程序动态读取工具注册表,生成工具描述,再拼接到提示词中。这样才能实现“新增一个工具,不用改提示词和循环代码”。
9.3 异常处理要下沉到工具层
不要在代理循环里做大量的错误重试。每个工具函数内部自行捕获异常,返回结构化错误信息,例如:
{ "success": false, "error": "请求超时,请稍后重试" }这样模型可以根据错误信息决定是否更换替代方案,而不是让整个代理进程崩溃。
9.4 生产环境必须做权限控制
在正式环境,不要暴露一个不受限制的/tools/call接口。建议添加两层控制:
- 认证:使用 API Key 或 OAuth 2.0 校验调用方身份。
- 工具白名单:根据用户角色返回不同工具集,普通用户不能调用管理类工具。
最小权限原则在这里同样适用,代理能调用什么工具,决定了它可能造成什么影响。
9.5 成本控制与速率限制
本地模型虽然没有 token 费用,但有计算资源成本。建议在代理入口设置请求频率限制,避免并发过高导致机器过载。同时记录每次任务的耗时和 token 数量,便于评估单位任务成本。
10. 总结与下一步学习路线
本文没有停留在“WebMCP 是个新概念”的层面,而是完整落地了一套 AI 代理助手:本地模型负责推理,工具函数提供外部能力,代理循环完成调度,最后用 FastAPI 暴露为可访问的 Web 服务。这套架构里,WebMCP 思路的本质是用协议化解耦“模型”和“工具”,让代理能力可以逐步沉淀、复用、组合。
如果你已经完成了本文的例子,下一步建议沿着三条线深入:
- 工具生态:继续接入更多工具,比如数据库查询、日历操作、企业 IM 通知。
- 模型能力:尝试在代理中加入长文本记忆、向量检索、知识库路由等机制。
- 工程治理:完善任务队列、权限体系、日志监控和成本统计,把脚本打磨成真正的交付物。
现在最值得做的不是囤积几百个工具包,而是把你手头最重复、最耗时、最标准化的一项工作,先交给代理跑起来,再逐步优化。跑通第一个自动化任务,比研究一百个新概念更有价值。如果本文对你有帮助,建议收藏备用,后续实践时可以对照排查。