Yuxi MySQL 报表技能(mysql-reporter):从 SQL 查询到可视化图表的完整实战指南
2026/9/17 22:08:49 网站建设 项目流程

Yuxi MySQL 报表技能(mysql-reporter):从 SQL 查询到可视化图表的完整实战指南

【免费下载链接】Yuxi可私有部署的多租户知识智能体平台:统一 RAG、知识图谱、多智能体、MCP/Skills、沙盒与权限管理。Self-hosted knowledge agent platform for RAG, knowledge graphs and multi-agent workflows.项目地址: https://gitcode.com/GitHub_Trending/yu/Yuxi

本篇技术指南以 Yuxi 内置技能mysql-reporter(位于 backend/package/yuxi/agents/skills/buildin/mysql-reporter/SKILL.md)为核心,系统讲解如何让 Agent 通过沙盒终端脚本安全地查询 MySQL 数据库、探查表结构与字段语义、执行只读 SQL,并借助 Charts MCP 生成可视化报表。读完本文,你将掌握该技能的完整操作流程、环境变量配置边界、安全校验机制(SQL 注入拦截、超时控制、结果截断)以及它与 Yuxi Skill 运行时(依赖解析、授权投影)的集成原理,能够直接在私有部署的多租户知识智能体平台上复现并扩展"查询数据库 → 生成业务报表"的能力。

技能定位:Yuxi 内置技能体系中的"数据库报表"模块

Yuxi 是一个可私有部署的多租户知识智能体平台,其 Agent 能力通过 Skill(技能)机制进行编排。内置技能统一在 backend/package/yuxi/agents/skills/buildin/init.py 中注册,mysql-reporter是其中之一,其注册信息如下:

BuiltinSkillSpec( slug="mysql-reporter", source_dir=_SKILLS_ROOT / "mysql-reporter", description="基于 MySQL 数据库生成查询报表和可视化图表,适合分析业务指标、统计趋势,并用 Charts MCP 展示结果。", version="2026.06.05", mcp_dependencies=("mcp-server-chart",), ),

从这份声明可以看出两个关键事实:

  • 该技能依赖 MCP 服务mcp-server-chart(即文档中提到的 "Charts MCP"),用于把查询结果渲染为图表;
  • 技能的元数据(slug、description、version)来自 SKILL.md 的 frontmatter,而 Yuxi 的 Skill 解析器会校验 frontmatter 中的nameslugdescription字段(见 backend/package/yuxi/agents/skills/service.py 中_parse_skill_markdown的校验逻辑)。

技能目录结构如下:

buildin/mysql-reporter/ ├── SKILL.md # 技能定义:流程、约束、允许的工具 └── scripts/ ├── _mysql_common.py # 共享连接工具:配置加载 + 连接创建 ├── list_tables.py # 列出库中所有表 ├── describe_table.py # 描述指定表结构 └── query.py # 执行只读 SQL 查询

一、技能工作原理:终端脚本 + 图表工具的组合式报表

根据 SKILL.md 的定位描述,"MySQL 报表技能"的目标是:

根据用户的指令,通过终端脚本访问 MySQL 数据库,并结合图表绘制工具构建 SQL 查询报告。

典型使用场景包括:统计销售数据、分析用户行为、生成业务报表、查询业务指标等。当用户在对话中提出这类需求时,技能就会被激活。它不直接暴露任意 MySQL 客户端给 Agent,而是通过scripts/下三个受控的 CLI 脚本提供受限的数据库访问能力,从机制上约束 Agent 只能执行白名单内的只读操作(详见下文安全机制部分)。

二、标准操作流程(7 步)

技能文档给出了 Agent 执行报表任务的完整流程,每步都对应具体的 CLI 操作:

  1. 理解用户指令:明确报表的需求和目标(指标口径、时间范围、分组维度、输出形式);
  2. 进入技能目录:通过 terminal 执行cd /home/gem/skills/mysql-reporter(该路径是沙盒中技能投影后的目录;在 Yuxi 的 Skill 运行时中,用户授权技能会被投影到只读的虚拟技能路径,见 backend/package/yuxi/agents/skills/runtime.py 中build_runtime_skillsVIRTUAL_SKILLS_PATH/{slug}/SKILL.md的映射);
  3. 查看可用表:执行uv run scripts/list_tables.py;如果脚本提示缺少 MySQL 配置,按"环境变量缺失处理"一节回复用户,而不是自行猜测;
  4. 查看表结构(必要时):执行uv run scripts/describe_table.py --table 表名
  5. 执行查询:生成正确且高效的只读 SQL,通过uv run scripts/query.py --sql "SQL语句" --timeout 60获取结果;
  6. 生成图表:使用 Charts MCP(即mcp-server-chart)将结果可视化为图表;
  7. 嵌入报表:将图表以 markdown 图片格式(描述)嵌入最终报表。

三个脚本均使用 uv 的脚本依赖声明运行(PEP 723 内联依赖元数据,见各脚本文件头部的# /// script注释块,依赖pymysql>=1.1.0),因此无需手动安装依赖即可执行。

三、环境变量:Agent 沙盒专属配置

技能文档强调了一个容易踩坑的关键约束:

脚本只读取 Agent 沙盒中的环境变量,不读取后端.env或 Docker Compose 变量。

这意味着 MySQL 连接配置必须在**个人设置中的「沙盒环境变量」**里配置,而不是在部署配置文件里。这一点在 scripts/_mysql_common.py 的load_mysql_config()中有直接体现——它只从os.getenv读取:

变量必填默认值说明
MYSQL_HOSTMySQL 主机地址
MYSQL_USER连接用户名
MYSQL_PASSWORD连接密码(敏感,严禁输出到报表)
MYSQL_DATABASE目标数据库名
MYSQL_PORT3306端口号
MYSQL_DATABASE_DESCRIPTION"默认 MySQL 数据库"数据库业务说明,用于辅助 Agent 理解表和指标含义

配置加载逻辑(源码级细节):

config: dict[str, Any] = { "host": os.getenv("MYSQL_HOST"), "user": os.getenv("MYSQL_USER"), "password": os.getenv("MYSQL_PASSWORD"), "database": os.getenv("MYSQL_DATABASE"), "port": int(os.getenv("MYSQL_PORT") or "3306"), "charset": "utf8mb4", "description": os.getenv("MYSQL_DATABASE_DESCRIPTION") or "默认 MySQL 数据库", }

四个必填项任一缺失时,会抛出MySQLConnectionError,错误信息形如MySQL configuration missing required key: host, please check your environment variables.

缺失配置时的正确处置(技能文档明确要求):

  • 不要继续猜测连接信息或编造报表;
  • 明确告诉用户:需要在个人设置 → 沙盒环境变量中配置缺失的MYSQL_*变量;
  • 提醒用户:保存后仅对新建沙盒生效,需要重新发起任务或新建会话后再执行。

关于沙盒环境变量"仅对新建沙盒生效"的语义,可以从 Yuxi 的沙盒工作区机制推断:Agent 沙盒是独立的运行时环境,环境变量随沙盒创建时注入,已有沙盒不会热更新配置,因此技能文档要求"重新发起任务或新建会话"以获得全新的沙盒实例。

四、三个 CLI 脚本的源码级解析

4.1 共享连接层_mysql_common.py

这是三个脚本共同的依赖模块(单元测试 backend/test/unit/agents/skills/test_mysql_reporter_scripts.py 中test_mysql_reporter_scripts_share_common_connection_helpers验证了三个脚本引用的load_mysql_configcreate_connection正是来自该模块),负责:

  • 配置加载:见上文,从环境变量读取并校验必填项;
  • 连接创建create_connection()内置 3 次重试,采用指数退避(time.sleep(2 ** attempt),即 1s、2s),连接参数包括connect_timeout=10read_timeout=60write_timeout=30autocommit=True、游标使用DictCursor(返回字典形式的行,便于按列名取值)。

4.2list_tables.py:列出全部表

  • 命令:uv run scripts/list_tables.py
  • 内部执行SHOW TABLES,将结果逐行列出;
  • 若配置了MYSQL_DATABASE_DESCRIPTION,会在输出顶部附上"数据库说明: {description}",帮助 Agent 理解业务上下文(如"销售库");
  • 空库时返回"数据库中没有找到任何表";
  • 出错时向 stderr 输出"获取表名失败: {异常}"并返回退出码 1。

4.3describe_table.py:描述表结构

  • 命令:uv run scripts/describe_table.py --table 表名--table为必填参数);
  • 输出格式为制表符分隔的表格:字段名 / 类型 / NULL / 键 / 默认值 / 额外 / 备注;
  • 通过查询information_schema.COLUMNS补充字段注释(COLUMN_COMMENT),并执行SHOW INDEX FROM汇总索引信息(如PRIMARY: id, user_id),这两步失败时静默降级,不影响主结构输出;
  • 安全校验MySQLSecurityChecker.validate_table_name()要求表名匹配^[a-zA-Z_][a-zA-Z0-9_]*$(字母/下划线开头,仅含字母数字下划线),非法表名直接抛出ValueError("表名包含非法字符,请检查表名"),杜绝表名注入。单元测试test_mysql_reporter_describe_table_name_security_validates_known_cases覆盖了users_audit_log通过,1usersuser-nameusers;drop被拒绝的场景。

4.4query.py:执行只读 SQL 查询

命令格式:uv run scripts/query.py --sql "SQL语句" --timeout 60

  • --sql:必填,要执行的 SQL;
  • --timeout:可选,默认 60 秒,合法范围为1~600 秒validate_timeout校验),超时抛出QueryTimeoutError
查询超时机制

查询在单线程线程池(ThreadPoolExecutor(max_workers=1))中执行,主线程通过future.result(timeout=timeout)等待。超时后取消 future、关闭连接并抛出QueryTimeoutError,从而避免信号处理带来的生成器问题(源码注释明确说明了这一设计动机)。

结果格式化与截断

查询结果以 markdown 表格输出(含表头分隔线),默认最多展示 50 行;总字符数超过 10,000 时按行截断,并给出警告:

⚠️ 警告: 查询结果过大,只显示了前 N 行(共 M 行)。建议使用更精确的查询条件或使用 LIMIT 子句来减少返回的数据量。

单列宽度最大 50 字符,防止超长字段破坏排版。

智能错误提示

build_query_error()会根据异常特征给出针对性建议:

  • 超时 → 建议减少数据量(WHERE 过滤)、使用 LIMIT、或增大--timeout(最大 600 秒);
  • table ... doesn't exist→ 建议运行scripts/list_tables.py查看可用表名;
  • column ... doesn't exist→ 建议运行scripts/describe_table.py查看表结构;
  • SQL 中出现%被当作参数占位符时 → 提示将百分号写成双百分号%%或改用参数化查询。

五、安全机制:只读校验与注入防护(源码级证据)

query.py中的MySQLSecurityChecker.validate_sql()实现了多层防护,这是该技能安全设计的核心:

  1. 注释剥离:先移除--行注释与/* ... */块注释,避免用注释绕过白名单判断;
  2. 语句白名单:SQL 必须以SELECTSHOWDESCRIBEEXPLAIN之一开头(ALLOWED_OPERATIONS);
  3. 危险关键字黑名单DROPDELETEUPDATEINSERTCREATEALTERTRUNCATEREPLACELOADGRANTREVOKESETCOMMITROLLBACKUNLOCKKILLSHUTDOWN全部禁止;
  4. 多语句拦截:剥离结尾分号后若语句内部仍含;,判定非法(阻止SELECT ...; DROP TABLE ...这类拼接攻击);
  5. 注入特征检测:正则匹配or 1=1union selectexec(xp_cmdshellsleep(benchmark(waitfor delay等模式,以及; 危险关键字组合。

单元测试test_mysql_reporter_query_security_validates_sql_and_timeout给出了完整用例矩阵,例如:

输入判定
SELECT * FROM users✅ 通过
show tables/DESCRIBE users/EXPLAIN SELECT ...✅ 通过
SELECT 1;(单个结尾分号)✅ 通过
DELETE FROM users❌ 拒绝
SELECT * FROM users WHERE id = 1 OR 1=1❌ 拒绝
SELECT * FROM users UNION SELECT password FROM admin❌ 拒绝
SELECT * FROM users; DROP TABLE users❌ 拒绝
/* 多行注释 */ SELECT 1✅ 通过(注释被剥离后白名单命中)

超时参数的校验同样严格:必须为int且在 1~600 之间,None0601、字符串"60"均被拒绝。

六、关键约束:Agent 必须遵守的行为红线

技能文档明确列出了 Agent 在执行报表任务时的约束,这些约束从产品层面对齐了上文的代码级安全机制:

  • SQL 正确且高效:避免全表扫描,应善用索引(可先通过describe_table.py查看索引信息)与LIMIT
  • 必须走本技能脚本:MySQL 操作一律通过scripts/下的 CLI 脚本执行,不要调用平台内置的 MySQL tools(内置 MySQL 工具可能不具备同样的只读白名单与审计能力);
  • 敏感信息保护:不得在报表或错误说明中输出MYSQL_PASSWORD等敏感环境变量的值,只能说明缺少哪些变量名
  • 图表必须显式嵌入:Charts MCP 的返回结果默认不会渲染,最终报表必须以描述的 markdown 图片格式嵌入;
  • 只输出结论:最终回复只包含与报表相关的结论,不要返回原始 SQL 查询语句。

七、允许的工具清单

技能运行时只向 Agent 暴露以下工具集(与 SKILL.md 的"允许的工具"一节一致):

  • terminal:执行scripts/list_tables.pyscripts/describe_table.pyscripts/query.py三个受控脚本;
  • Charts MCPmcp-server-chart):生成可视化图表;
  • 网络检索工具:仅在必要时补充背景信息。

工具的白名单化正是 Yuxi Skill 依赖机制的落地:技能在BuiltinSkillSpec中声明mcp_dependencies=("mcp-server-chart",),运行时再通过resolve_skill_gated_tools/build_dependency_bundle(见 backend/package/yuxi/agents/skills/runtime.py)把声明的 MCP 与工具按需挂载到当前 Agent Run,未授权的工具不会出现在该技能上下文中。

八、与 Yuxi Skill 运行时的集成方式

要理解该技能如何"生效",可以看 Yuxi Skill 运行时的三个环节:

  1. 注册与安装:内置技能由BUILTIN_SKILLS列表统一注册(slug 为mysql-reporter,版本2026.06.05);用户侧启用后,技能数据写入 Skill 表(见 backend/package/yuxi/agents/skills/repository.py),内置技能默认以global读范围共享(BUILTIN_SKILL_SHARE_CONFIG = {"access_level": "global", ...});
  2. 授权投影:用户可访问的技能会被同步为只读投影目录(sync_user_accessible_skills,见 backend/package/yuxi/agents/skills/service.py),即技能文档中cd /home/gem/skills/mysql-reporter所指向的沙盒内路径的来源;投影过程中会拒绝符号链接并做哈希比对,保证沙盒内看到的技能内容是可信快照;
  3. 运行时快照:每次 Agent Run 启动时,resolve_runtime_skills_for_context解析出effective_skills(含依赖闭包展开)与runtime_skills元数据,并把根级SKILL.md的内容注入上下文,Agent 据此理解技能的操作流程与约束(见 backend/package/yuxi/agents/skills/runtime.py)。

因此,mysql-reporter/SKILL.md不仅是一份给人看的说明,更是运行时注入给模型的行为规范——流程、环境变量处理、关键约束都会被模型作为执行依据。

九、实战演练:从一条用户指令到一张报表

结合以上内容,一个完整的典型调用链如下(以"统计最近 7 天各地区的销售额"为例):

用户 → "帮我统计最近 7 天各地区的销售额,画成柱状图" │ ├─ 1. 理解需求:指标=销售额,维度=地区,时间=近7天,输出=柱状图 ├─ 2. cd /home/gem/skills/mysql-reporter ├─ 3. uv run scripts/list_tables.py # 确认有 orders、regions 等表 ├─ 4. uv run scripts/describe_table.py --table orders # 确认字段名与注释 ├─ 5. uv run scripts/query.py --sql "SELECT r.name, SUM(o.amount) AS sales FROM orders o JOIN regions r ON o.region_id = r.id WHERE o.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY r.name ORDER BY sales DESC" --timeout 60 ├─ 6. 调用 Charts MCP 生成柱状图,得到图片 URL └─ 7. 在报表中嵌入 各地区近7天销售额,只输出业务结论

执行第 3 步时若出现MySQL configuration missing required key: xxx,Agent 应停止后续步骤,按"环境变量缺失处理"要求用户去个人设置补配沙盒环境变量,并说明需重新发起任务。

十、可验证的测试与文档依据

  • 技能定义:backend/package/yuxi/agents/skills/buildin/mysql-reporter/SKILL.md
  • 脚本实现:backend/package/yuxi/agents/skills/buildin/mysql-reporter/scripts/_mysql_common.pylist_tables.pydescribe_table.pyquery.py
  • 技能注册:backend/package/yuxi/agents/skills/buildin/__init__.py
  • 单元测试:backend/test/unit/agents/skills/test_mysql_reporter_scripts.py(覆盖共享连接工具、缺失配置报错、SQL/表名/超时校验矩阵、投影后 CLI 行为)
  • 运行时与授权:backend/package/yuxi/agents/skills/runtime.pybackend/package/yuxi/agents/skills/service.pybackend/package/yuxi/agents/skills/repository.py
  • 相关能力文档:docs/agents/skills-management.md(Skill 管理与授权)、docs/agents/mcp-integration.md(Charts MCP 接入)

总结

mysql-reporter技能展示了 Yuxi 平台上"受限数据库访问 + 可视化报表"的标准范式:通过终端脚本提供只读白名单(仅SELECT/SHOW/DESCRIBE/EXPLAIN)、注入拦截(多语句、危险关键字、注入特征多重校验)、资源保护(1~600 秒超时、10,000 字符与 50 行结果截断)三层面管控,再叠加沙盒环境变量注入与敏感信息不落盘原则,让 Agent 既能自主完成从查表、看结构、写 SQL 到出图报表的完整链路,又不会触碰数据写权限与凭据安全底线。对于需要在私有化环境中做业务指标统计、销售分析、用户行为洞察的团队,直接启用该内置技能并按文档配置沙盒环境变量,即可让 Agent 立刻具备可靠的 MySQL 报表生产能力。

【免费下载链接】Yuxi可私有部署的多租户知识智能体平台:统一 RAG、知识图谱、多智能体、MCP/Skills、沙盒与权限管理。Self-hosted knowledge agent platform for RAG, knowledge graphs and multi-agent workflows.项目地址: https://gitcode.com/GitHub_Trending/yu/Yuxi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询