尧图精选

AI Skill查数据难?scripts、CLI、MCP三条通道帮你打通

🕒 发布时间:2026/10/2 16:52:09 📁 来源:尧图网络
1. Skill查不了数据的病根知识进来了管道没接上1.1 Skill到底是什么它是说明书不是执行器先回到最基本的问题。很多人从社区下载了一个AI Skill比如AI备课Skill、AI像素动画Skill打开目录看见一个SKILL.md里面有步骤、有示例、有注意事项就觉得装好了AI应该会了。结果真到用的时候AI要么给你生成一段看似正确的SQL要么直接说没有权限访问就是给不了你要的数据。其实SKILL.md是一本给模型看的作业指导书。模型读到它知道这件事应该按什么流程做、做到什么标准、用什么格式输出。它改变的是模型的行为模式不会自动给模型注入新的权限、新的网络通道或新的数据源。这个区别很关键。你可以把Skill想成给新来的实习生一份流程图实习生看了流程图知道第一步开电脑、第二步打开数据库客户端、第三步执行查询。但如果电脑没通电、客户端没装、账号没开通那流程图再详细他也查不了数据。AI Skill也一样查不了数据往往不是它不会而是它没有通路。搞清楚这一点你就明白为什么很多人装了Skill还是查不到数据了Skill解决的是模型知道怎么做的问题而真正的数据查询是模型有没有办法执行的问题。后者需要的是接口调用能力也就是本篇文章要讲的核心——scripts、CLI、MCP。1.2 查不了数据的四个典型原因我见过的Skill装好但查不到数据的案例九成都能归到下面四类。第一是权限。Skill里写了一堆API调用示例但模型执行时用的API key要么没配要么scope不够服务端直接返回403。数据库连接字符串只写在某台跳板机的环境变量里本地模型根本没有。这类问题最隐蔽因为Skill本身看起来完全正常文档也没写错。第二是网络。数据目标在公网上当前环境是隔离内网或者目标服务监听在127.0.0.1上模型在另一个容器里执行命令根本访问不到。DNS解析失败、防火墙拦了非常规端口都会让接口调用静默失败。这种问题你代码写得再对也没用得先确认调用方和数据源之间是否真的通。第三是鉴权细节。token过期了Skill里给的是一个月前的样例headers里的签名算法变了模型还按旧格式拼。还有一类特别容易栽鉴权信息要求放在header而不是query参数里Skill文档里没写清楚模型凭常识放错位置服务端自然不认识。第四是上下文没传达到位。这个最容易被忽略。有些Skill只写了如果要查询数据请调用内部接口但没写接口地址、必填参数、返回结构。模型知道有这么个东西却不知道入口在哪最后只能靠猜或者干脆说我无法访问。第三、第四个原因其实是同一个问题的两面——Skill与外部世界的连接契约没有写全。1.3 我是怎么排查的先分清不会调还是调不动遇到查不了数据我第一反应不是改Skill而是先做一次两步排查。第一步让模型自己说你打算用哪种方式去查如果它能说出我要先运行一个Python脚本脚本里用requests调用某个API那说明Skill的指令已经传到问题出在执行层。如果它支支吾吾说根据我的能力我无法直接访问那多半是Skill里根本没写清楚工具入口在哪问题出在契约层。第二步把Skill里的调用链路手动跑一遍。手动运行脚本、手动敲命令、手动测试MCP server的连通性。这一步能立刻区分是环境问题还是代码问题。我强烈建议Skill在使用前先做一次最小冒烟测试不经过模型你直接在命令行把一次真实查询跑通。只要这一步成功模型那边80%的报错都是契约或参数问题这一步失败你换什么Prompt都白搭。2. scripts、CLI、MCP三条通道的分工逻辑不要选错赛道把三条通道放在同一张图景里看Skill要获取数据本质上只有三种方式可以让模型和外部的数据源交上话。2.1 scriptsSkill里直接放一段代码模型照着执行scripts指的是Skill目录中携带、或模型动态生成的可执行脚本。模型读取SKILL.md后会得到一个明确指令你可以运行scripts/query.py来查询数据。脚本内部封装了HTTP请求、鉴权、解析逻辑模型不需要知道底层细节只要知道怎么传参数、怎么读结果。这种方式适合目标接口明确、逻辑稍复杂、需要稳定复用的场景。比如查订单数据你要拼签名、拼参数、处理分页如果让模型每次临时写代码既慢又容易出错把这段逻辑固定成脚本Skill就可以像工具箱一样反复调用。很多国产AI客户端里的API接入技巧本质上也是这个套路——把接口调用封装成一段可执行文件让模型只负责传参和解读结果。一个细节脚本的执行环境由客户端决定。同一个Skill在桌面客户端里和命令行Agent里运行Python解释器版本、依赖版本都可能不同。所以scripts方式要自带依赖声明或者干脆用纯标准库实现否则换个环境就躺平。2.2 CLI把本机已有的能力当外挂CLI是很多人忽视的一条高效通道。它的思路更直接模型不写HTTP代码而是执行一条命令行命令。命令的标准输出天然就是返回值退出码天然就是错误码。比如你本地装了一个sqlite3Skill里就让模型去执行sqlite3 数据库 select ...你本地装了curlSkill里就让模型curl某个URL。对于数据就在本机、工具链已经存在的场景CLI比scripts更快因为不用重新实现一遍别人已经写好的功能。GitHub CLI、GitLab CLI这类工具装好以后进Skill配置里就是一条命令的事无需专门写代码。CLI最大的坑在于环境一致性模型执行命令时的PATH可能和你当前终端不一样环境变量可能没有继承某些交互式命令会被直接卡死。这些后面专门讲。2.3 MCP把怎么连升级为连哪个serverMCPModel Context Protocol是另一种思路。前面的scripts和CLI都把连接细节写死在Skill里MCP则把连接本身抽出来变成一个独立的标准服务。Skill只需要告诉模型查询数据请调用名称为xxx的MCP工具。至于这个工具背后连的是哪个数据库、用什么协议、怎么鉴权都封装在MCP Server里。这就像USB-C接口你不需要关心充电器是哪个牌子的只要接口统一插上就能用。MCP对于多人协作、多Agent复用、数据源频繁变更的场景特别有价值——改动在Server侧完成Skill一行都不用改。热词里常提到的MCP是软件协议还是硬件协议其实它就是一个应用层协议和HDMI是影音传输标准是一个概念层级的东西只是它服务的主体是AI应用与工具服务。2.4 三者的边界一张表看懂维度scriptsCLIMCP调用入口运行一段脚本执行一条命令调用MCP Server的Tool/Resource数据回来方式脚本打印结果到标准输出命令标准输出文本协议定义的JSON结构化返回鉴权放哪里脚本内部key、签名命令环境变量/配置文件MCP Server侧统一管理依赖条件脚本运行时Python/Node本机CLI工具MCP客户端 MCP Server进程适合场景逻辑复杂、接口固定已有成熟命令行工具、本地数据多系统复用、标准协议、多人协作改数据源要动哪里改Skill里脚本改命令参数只改Server侧Skill不动我自己的判断基准很简单逻辑固定且要重复用的写scripts本机已经有靠谱工具的就用CLI涉及外部系统、多人协作、连接形态可能变化的优先MCP。3. scripts方式实操从零搭一个能查订单数据的Skill这一节用具体例子把scripts路线走通。假设场景你的团队有一个内部订单查询APIGET /orders?statusxxx需要带Authorization header鉴权返回JSON数组。我们要做一个Skill让AI直接能查订单。3.1 目录结构与SKILL.md骨架Skill本质是一个目录推荐结构如下order-query-skill/ ├── SKILL.md └── scripts/ └── query_orders.pySKILL.md里最关键的不是案例而是把脚本的调用契约写清楚。我的写法参考# Order Query Skill ## 用途 查询订单数据。当用户询问订单列表、订单状态、某客户订单时使用本Skill。 ## 执行方式 运行 scripts/query_orders.py 执行查询 python3 scripts/query_orders.py --status 订单状态 [--limit 条数] ## 必填参数 - status: pending / paid / shipped / closed ## 返回说明 脚本输出JSON数组。每条订单包含 - order_id: 字符串 - amount: 数字单位元 - status: 字符串 - created_at: ISO 8601格式时间 ## 注意事项 - 脚本退出码非0时向用户说明查询失败不要编造结果 - 接口鉴权失败返回403时提示用户检查API KEY配置这里有一个很多人会犯的错SKILL.md写得像散文模型读着爽但不一定能正确调用。Skill文档应该像接口文档把参数、返回结构、错误码写得越机械越好模型才不会自由发挥。3.2 写一个带鉴权、超时、流式输出的Python脚本脚本用标准库加requests突出稳定性。核心代码#!/usr/bin/env python3 import argparse import json import os import sys import requests API_BASE os.getenv(ORDER_API_BASE, https://api.example.com) API_TOKEN os.getenv(ORDER_API_TOKEN, ) def fetch_orders(status: str, limit: int 20) - list: headers {Authorization: fBearer {API_TOKEN}} params {status: status, limit: limit} try: resp requests.get(f{API_BASE}/orders, headersheaders, paramsparams, timeout15) resp.raise_for_status() return resp.json().get(data, []) except requests.Timeout: print(ERROR: 请求超时, filesys.stderr) sys.exit(2) except requests.HTTPError as e: print(fERROR: HTTP {e.response.status_code}, filesys.stderr) sys.exit(3) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--status, requiredTrue) parser.add_argument(--limit, typeint, default20) args parser.parse_args() orders fetch_orders(args.status, args.limit) print(json.dumps(orders, ensure_asciiFalse))几个细节值得说。第一超时必须显式设置默认requests没有超时会一直挂着模型会以为系统死了。第二错误全部写进stderr并且用非零退出码这样模型能区分正常空结果和调用失败。第三token从环境变量读取而不是写死在脚本里。Skill通常是共享分发的写死等于泄露密钥。如果你的数据源走的是流式SSE接口现在很多大模型推理接口都是这种思路类似但解析要单独处理。常见做法是用requests带streamTrue然后逐行读取data:前缀的JSON。无论scripts、CLI还是MCP流式解析逻辑都建议封装成独立模块别散落在Skill的各个角落。3.3 给模型一本契约说明书脚本写好了真正决定成败的是SKILL.md里那几行描述。模型不是人它不会看着例子举一反三它严格按文档理解。我见过SKILL.md写查询订单返回订单信息结果模型把order_id当成数字传进去或者把amount当字符串拼接输出格式完全对不上。所以契约描述必须包含三块。第一块是参数语义status可取值有哪些limit的范围是什么。第二块是返回结构顶层是数组还是对象字段名和类型。第三块是错误语义退出码、错误信息分别代表什么模型应该怎么向用户转述。如果你想让模型做到操作可解释建议在SKILL.md里加一条执行任何外部查询前先用自己的话向用户复述要做什么、调用什么接口、传什么参数。实测这能大幅降低模型擅自修改参数的情况。3.4 本地验证与常见报错写完脚本先别急着让AI去调手动跑三行python3 scripts/query_orders.py --status paid echo $?手动跑通了再进入Agent会话。我遇到最多的报错是下面三种403 Forbidden几乎都是API token没设置或权限不够。检查环境变量ORDER_API_TOKEN在Agent进程里是否存在不要在Skill配置里写token。超时内网服务延迟高、DNS解析慢把timeout从15调大到30或者加一个重试逻辑。JSON解析失败接口返回了非JSON内容比如网页报错页。脚本不要直接resp.json()先判断Content-Type或者把原始文本一并打印到stderr方便排查。4. CLI方式实操不写脚本用现成命令把数据拉回来scripts适合从零搭建CLI适合已有工具直接复用。很多数据其实不用写任何代码就能拿到。4.1 为什么CLI是容易被忽略的效率通道我见过太多人为了查一个本地SQLite数据库专门写一个Python脚本封装sqlite3其实系统本身就自带CLI。当本机已经存在成熟命令行工具时Skill只需要告诉模型执行什么命令剩下的解析工作交给文本本身。CLI的另一个优势是输出格式通常已经优化过。你执行一条命令返回的是人可读的表格、JSON或CSV模型天然擅长理解这些文本。而scripts方式里每多一层自建脚本就多一个出错点。如果目标只是把数据拿到对话里来CLI是成本最低的一条路。4.2 一个具体例子用sqlite3和curl完成两种数据查询假设我们要做一个本地日志检索Skill。数据在/var/log/app.db这个SQLite库里有一个access_log表。SKILL.md可以这么写## 执行方式 查询本地数据库时使用sqlite3命令 sqlite3 /var/log/app.db SELECT * FROM access_log WHERE path LIKE %关键词% LIMIT 20; 输出为制表符分隔文本注意第一行是列名。 ## 注意事项 - 命令可能返回空输出表示没有匹配数据 - 不要在高权限下执行 - SQL中用单引号包裹字符串再比如查一个公网API直接用curlcurl -s -H Authorization: Bearer $TOKEN https://api.example.com/orders?statuspaid | jq .data[:20]把这条命令写进SKILL.md然后告诉模型输出是JSON请提取关键字段并整理成表格。整个流程没有任何自定义代码全部复用系统工具。你可以看到CLI和scripts的区别不在于能不能拿到数据而在于要不要为了拿数据去写新代码。4.3 命令输出的交通规则exit code、stdout、stderrCLI和scripts有一个共同的、经常被忽略的原则模型必须学会看三分屏。标准输出stdout是结果标准错误stderr是日志退出码是成败标志。很多Agent默认只关心stdout结果命令已经失败了它还在解析一段错误信息之后残留的旧输出。我的经验是在SKILL.md里明确写执行命令后先查看退出码非0即失败把stderr报告给用户只有退出码为0时才去解析stdout。这一步能规避大量模型假装查到数据的情况。自动化脚本里务必通过按;还是连接命令来区分执行结果否则后续命令会在失败后继续跑。4.4 CLI的坑PATH不一致、环境变量丢失、交互式命令慎用CLI方式有三个高频坑。第一个是PATH不一致。你在交互终端里配了~/.local/bin但Agent进程启动时可能不加载shell配置导致命令not found。解决方法是SKILL.md里用绝对路径执行命令或者在命令前加export PATH$PATH:...。第二个是环境变量丢失。和scripts方式一样token、数据库连接串通常放在环境变量里但Agent会话中的环境变量未必继承了你终端的环境。建议在Skill目录里放一份.env.example把读取环境变量这一步写成固定动作让模型每次执行前先检查。第三个是交互式命令。凡是需要提示符交互、需要手动输入密码的命令比如ssh、带密码的CLI、某些数据库客户端在Agent里会直接挂起。能不用就不用必须用时用--password-stdin或连接URI方式绕开交互且绝对不要把密码明文放在命令参数里。5. MCP方式实操把Skill接到标准插座上scripts和CLI本质都在操Agent自己的手MCP则是给Agent装一副万能插座。5.1 MCP的一分钟科普三种能力和通信格式MCP协议定义了客户端Agent与服务器MCP Server之间的标准通信方式。服务端向外暴露三种能力Tools动态工具可执行操作、查数据、Resources资源通常是静态文件或文档内容、Prompts可复用的提示词模板。底层传输一般分stdio本地子进程通信和HTTP远程服务消息格式走JSON-RPC 2.0。对这个标题的场景而言你只要记住一件事当Skill需要连接外部系统时模型不用知道系统里面怎么实现只需要知道有一个叫xxx的Tool可以查询数据参数是yyy。连接和处理都封装在MCP Server里。很多关于MCP的搜索热词都是在问MCP是软件协议还是硬件协议这里统一回答MCP是软件协议全称Model Context Protocol它解决的是AI应用与外部工具服务之间的标准化连接问题和USB这类硬件接口规范不是一回事但在设计哲学上有共通点——统一接口、即插即用。5.2 本地起一个MCP Server然后让Skill去调以最常见的本地stdio模式为例。在Agent的MCP配置中加一段{ mcpServers: { order-db: { command: python, args: [/path/to/mcp_server.py], env: { ORDER_DB_PATH: /data/orders.db } } } }这个配置的意思是Agent启动时会拉起这个Python进程两者通过stdin/stdout上的JSON-RPC消息通信。Skill这边只需要在SKILL.md里写查询订单时使用MCP工具 order-db 中的 query_orders 工具。 参数status订单状态。模型看到这段文字后会自动通过MCP客户端去调用不需要知道数据库在哪、用什么驱动。本地启动MCP Server教程里最常翻车的就是路径问题和环境变量问题把命令路径、工作目录、env逐项确认清楚基本能省一半调试时间。不同SDK版本在注册Tool和Resource时的API略有差异所以这里我刻意不给伪代码避免你照着过时的写法去报错。你去官方示例里跑一遍hello tool把返回结构理解清楚再套到自己业务上比抄任何博客都靠谱。5.3 查数据用Tool还是Resource先判断静态还是动态很多人第一次写MCP Skill会纠结该暴露Resource还是Tool。我的判断标准很简单如果内容是固定的、不随参数变化用Resource如果需要每次查询都实时计算或查库用Tool。比如公司服务器信息清单适合做成Resource因为它是配置文件按日期查询订单必须做成Tool因为每次都会变。Resource在MCP里更像给Agent的参考资料它被动等待读取Tool更像可以拨打的号码主动接收参数并返回数据。查数据的场景九成是ToolResource适合把常量配置、说明文档喂给模型。5.4 MCP连不上的排查链路MCP方式的报错通常集中在三处启动失败、连接超时、调用被拒。我给一个标准排查顺序先看配置路径对不对再看server进程有没有起来再看能否在命令行手动跟server握手最后看模型是否有权限调用工具。具体来说如果报Failed to start MCP server先确认command可执行、args路径绝对化、env里的变量齐全如果报Connection closed看server进程是不是因为缺依赖直接崩了如果调用时报Method not found说明Tool名字没对全。每一步都能在启动日志里看到线索所以本地调试时一定先看进程日志别只盯着Agent界面的报错。5.5 常见集成场景VS Code、Dify、浏览器自动化现在很多产品都支持MCP配置比如VS Code的AI插件、Dify工作流中的Agent、浏览器自动化工具等。它们的接入思路完全一致在配置面板里声明mcpServers然后在Skill的说明文档里声明用什么工具查数据。唯一的差别只是配置文件入口不一样你只要把同一个MCP Server地址或本地命令填进去Skill侧的文字描述基本可以复用。举个例子你已经在Dify里配置了一个浏览器MCP那么在任意Skill里都可以写打开某个页面时使用浏览器MCP的open_url工具。Skill本身不需要知道浏览器怎么驱动它只负责把用户的意图翻译成对MCP工具的调用。6. 选型决策按数据路径选不按流行度选附带我的经验清单6.1 决策表遇到查不了数据该怎么选你的实际情况推荐方式原因接口逻辑复杂参数多要稳定复用scripts把复杂度封在脚本里模型只传参本机已有成熟CLI数据在本地文件或DBCLI零自定义代码最快见效多个Agent要共用同一数据源MCP连接在Server侧集中管理数据源连接信息经常变更MCPSkill不用改改Server配置即可临时一次性的查询CLIcurl等轻量、快速、用完即弃需要定制鉴权、重试、流式处理scripts编程语言控制力最强跨团队交付别人也要复用MCP scripts混合标准协议 核心逻辑脚本这个表不是绝对的但能帮你在纠结的两分钟里做出一个不后悔的决定。核心原则是改动越少越好依赖越简单越好。6.2 我的个人优先级判断我现在的习惯是能CLI就CLI能scripts就scripts必须MCP才MCP。CLI为什么排最前因为它最贴合复用已有的东西这一原则成本最低。scripts排第二因为需要定制逻辑的时候它能做到最精确。MCP反而更像架构决策只有当连接方式需要被标准化、或者多个Agent要共享才引入它。别被MCP很潮流带着走。一个只有你自己用的Skill你去起一个MCP Server等于为了拿一罐可乐装了一条灌装线。架构复杂度是有真实成本的调试一个stdio连接所花的时间通常比你用requests写15行脚本要多得多。6.3 一套能复制到任何Skill的避坑清单最后分享几个我踩了几次才形成的习惯几乎适用于任何AI Skill查数据的场景先手动验证再交给模型。任何脚本、命令、MCP Server先在命令行里跑通一次再做Skill文档。Skill文档要像接口文档不要像散文。参数、返回、错误码全部机械地列出。环境变量统一走.env或系统配置不要写死在Skill目录里。区分stdout和stderr退出码非0就当失败。所有外部调用设置超时宁可超时报错不要无限等待。给模型一个复述环节执行前先说明要调什么、为什么。记录一次最小冒烟日志把一次成功的调用过程存下来以后改Skill时回归测试。如果你现在正被装了Skill却查不了数据卡住建议不要急着去找更复杂的Skill或者换一个Agent而是先回到最简单的那条路把一条真实的数据查询从命令行手动跑通。跑通以后你用scripts、CLI还是MCP去包装它都只是形式问题跑不通再加多少层包装都是白搭。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →