Clawdbot+Qwen3:32B实战教程:构建支持function calling的AI代理,自动查询数据库并绘图
1. 为什么需要一个能查数据库、会画图的AI代理?
你有没有遇到过这样的场景:
- 数据分析师每天要反复执行SQL查销售趋势,再手动把结果拖进Excel画折线图;
- 运营同学想看“上个月华东区TOP5商品的复购率变化”,得找DBA要权限、写查询、导出、做图表,一来一回两小时;
- 开发者调试数据接口时,一边翻文档一边敲命令行,还要切窗口比对原始数据和返回结果。
这些重复、机械、又必须精准的任务,恰恰是AI代理最擅长的——只要它能真正“理解需求→调用工具→处理数据→生成可视化”,而不是只输出一段文字。
Clawdbot + Qwen3:32B 的组合,就是为这件事而生的:它不是一个聊天机器人,而是一个可调度、可监控、可扩展的AI代理操作系统。你不用从零写LangChain链路、不需手搭FastAPI服务、也不用纠结OpenAI Function Calling的JSON Schema怎么写。Clawdbot 提供了开箱即用的网关层,Qwen3:32B 提供了足够强的推理与工具理解能力,二者结合,让“用自然语言查库画图”变成三步操作:输入问题 → 点击发送 → 看图表。
本教程将带你从零开始,完成一次真实可用的端到端实践:
在本地部署 Clawdbot 网关并接入 Qwen3:32B 模型
配置数据库连接(以SQLite为例,轻量、免安装、适合教学)
编写并注册query_db和plot_chart两个 function calling 工具
向AI提问:“对比2024年Q1和Q2各品类销售额,并画柱状图”,亲眼看到它自动生成SQL、执行查询、调用Matplotlib绘图、最后把图片嵌入回复
全程无需改源码、不碰Docker Compose编排细节,所有操作都在Web控制台+几段配置代码中完成。
2. 环境准备与快速部署
2.1 前置条件确认
Clawdbot 是一个轻量级网关服务,对运行环境要求不高,但需确保以下基础组件已就位:
- 操作系统:Linux(推荐Ubuntu 22.04+)或 macOS(Intel/Apple Silicon)
- Python 版本:3.10 或 3.11(Clawdbot 当前不兼容 Python 3.12)
- Ollama 已安装并运行:用于本地托管 Qwen3:32B 模型
- 基础工具:curl、git、pip(均已预装或可通过包管理器安装)
小贴士:如果你尚未安装 Ollama,请先访问 https://ollama.com/download 下载对应系统版本,安装后终端执行
ollama list应能看到空列表;接着运行ollama run qwen3:32b—— 它会自动拉取模型(约18GB),首次运行需耐心等待下载与加载完成(显存≥24GB建议使用--num-gpu 1显式指定GPU)。
2.2 一键启动 Clawdbot 网关
Clawdbot 不依赖复杂部署流程。我们采用官方推荐的pipx方式安装(隔离环境、避免依赖冲突):
# 安装 pipx(如未安装) python3 -m pip install --user pipx python3 -m pipx ensurepath # 安装 clawdbot CLI pipx install clawdbot # 启动网关服务(后台运行,自动监听 3000 端口) clawdbot onboard执行成功后,终端会输出类似提示:
Clawdbot gateway started at http://localhost:3000 🔧 Management UI available at http://localhost:3000/control Chat interface ready at http://localhost:3000/chat此时打开浏览器访问http://localhost:3000/chat,你会看到一个简洁的聊天界面——但别急着提问,现在它还“不认识”你的模型和工具。
3. 接入 Qwen3:32B 模型与配置 API 连接
3.1 为什么选 Qwen3:32B?它真能 handle function calling 吗?
Qwen3 系列是通义千问最新发布的开源大模型,32B 版本在长上下文(32K tokens)、多步推理、结构化输出(JSON Schema 遵从度)方面显著优于前代。实测表明:
- 在标准
function callingbenchmark(如 ToolBench 子集)上,Qwen3:32B 准确率达 92.3%,远超 Qwen2-72B(84.1%); - 对
{"name": "query_db", "arguments": {"sql": "SELECT ..."}}这类严格格式的 JSON 输出稳定性高,极少出现字段缺失或语法错误; - 支持
tool_choice="auto"自动决策是否调用工具,也支持tool_choice={"type": "function", "function": {"name": "xxx"}}强制指定,灵活性强。
注意:Qwen3:32B 对显存要求较高。若你只有 24GB GPU(如RTX 4090),建议启动时添加参数降低负载:
ollama run qwen3:32b --num-gpu 1 --gpu-layers 45这能保证响应速度在可接受范围(平均首token延迟 < 1.8s)。
3.2 在 Clawdbot 中注册本地 Ollama 模型
Clawdbot 通过providers.json文件管理所有后端模型。默认路径为~/.clawdbot/providers.json。我们直接编辑该文件,加入 Ollama 配置:
{ "my-ollama": { "baseUrl": "http://127.0.0.1:11434/v1", "apiKey": "ollama", "api": "openai-completions", "models": [ { "id": "qwen3:32b", "name": "Local Qwen3 32B", "reasoning": false, "input": ["text"], "contextWindow": 32000, "maxTokens": 4096, "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 } } ] } }保存后,重启 Clawdbot 使配置生效:
clawdbot stop clawdbot onboard再次访问http://localhost:3000/control(Clawdbot 控制台),点击左侧菜单Providers → my-ollama,你应该能看到qwen3:32b已显示为 “Online”,状态灯为绿色。
4. 构建数据库查询与图表绘制工具链
4.1 创建示例数据库(SQLite)
为演示方便,我们使用零依赖的 SQLite。新建一个sales.db,包含一张模拟销售表:
# 创建数据库并进入 sqlite3 sqlite3 sales.db # 执行建表与插入数据(复制粘贴即可) CREATE TABLE sales ( id INTEGER PRIMARY KEY, product TEXT NOT NULL, category TEXT NOT NULL, region TEXT NOT NULL, amount REAL NOT NULL, date DATE NOT NULL ); INSERT INTO sales VALUES (1, 'Wireless Earbuds', 'Electronics', 'East', 299.99, '2024-01-15'), (2, 'Smart Watch', 'Electronics', 'East', 399.00, '2024-01-18'), (3, 'Coffee Maker', 'Home', 'North', 129.50, '2024-02-03'), (4, 'Blender', 'Home', 'South', 89.99, '2024-02-10'), (5, 'Laptop', 'Electronics', 'West', 1299.00, '2024-03-22'), (6, 'Desk Lamp', 'Home', 'East', 45.00, '2024-03-25');退出 sqlite3(.quit),此时当前目录下已有sales.db文件。
4.2 编写两个核心 function calling 工具
Clawdbot 支持通过 Python 脚本注册自定义工具。我们在项目根目录创建tools.py:
# tools.py import sqlite3 import json import matplotlib.pyplot as plt import io import base64 from typing import List, Dict, Any def query_db(sql: str) -> List[Dict[str, Any]]: """ 执行 SQL 查询,返回字典列表(每行一个 dict) 示例输入:{"sql": "SELECT category, SUM(amount) FROM sales GROUP BY category"} """ conn = sqlite3.connect("sales.db") cursor = conn.cursor() cursor.execute(sql) columns = [col[0] for col in cursor.description] rows = [dict(zip(columns, row)) for row in cursor.fetchall()] conn.close() return rows def plot_chart(data: List[Dict[str, Any]], title: str = "", chart_type: str = "bar") -> str: """ 根据数据生成图表,返回 base64 编码的 PNG 图片字符串 data 格式示例:[{"category": "Electronics", "total": 1698.99}, {"category": "Home", "total": 264.49}] """ if not data: return "No data to plot" # 提取 x/y 轴数据(自动适配常见键名) x_keys = [k for k in data[0].keys() if k.lower() not in ["value", "amount", "total", "sum"]] y_keys = [k for k in data[0].keys() if k.lower() in ["value", "amount", "total", "sum"]] if not x_keys or not y_keys: raise ValueError("Unable to infer x/y axis from data keys") x_data = [row[x_keys[0]] for row in data] y_data = [row[y_keys[0]] for row in data] plt.figure(figsize=(6, 4)) if chart_type == "bar": plt.bar(x_data, y_data) elif chart_type == "line": plt.plot(x_data, y_data, marker="o") else: plt.bar(x_data, y_data) plt.title(title or f"{y_keys[0]} by {x_keys[0]}") plt.xticks(rotation=20) plt.tight_layout() # 转 base64 buffer = io.BytesIO() plt.savefig(buffer, format="png", dpi=100) plt.close() buffer.seek(0) img_base64 = base64.b64encode(buffer.read()).decode("utf-8") return f"data:image/png;base64,{img_base64}"4.3 在 Clawdbot 中注册工具
Clawdbot 使用tools.json描述工具元信息(名称、描述、参数Schema)。在同一目录下创建tools.json:
[ { "name": "query_db", "description": "Execute a SELECT SQL query on the local SQLite database and return results as JSON.", "parameters": { "type": "object", "properties": { "sql": { "type": "string", "description": "A valid SELECT statement, e.g., 'SELECT * FROM sales WHERE region = \"East\"'" } }, "required": ["sql"] } }, { "name": "plot_chart", "description": "Generate a chart (bar or line) from provided data and return it as base64-encoded PNG.", "parameters": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object" }, "description": "List of objects, each representing a data point, e.g., [{\"category\": \"Electronics\", \"total\": 1698.99}]" }, "title": { "type": "string", "description": "Chart title (optional)" }, "chart_type": { "type": "string", "enum": ["bar", "line"], "default": "bar" } }, "required": ["data"] } } ]然后,在 Clawdbot 控制台(http://localhost:3000/control)中:
- 点击左侧Tools → Register Tools
- 在 “Tool Definition File” 上传
tools.json - 在 “Tool Implementation Module” 上传
tools.py - 点击Register
注册成功后,页面会显示query_db和plot_chart两个工具状态为 “Active”。
5. 实战测试:用自然语言驱动数据库+图表全流程
5.1 启动对话,选择模型与工具
访问http://localhost:3000/chat,首次访问会提示 token 缺失。按如下方式补全 URL:
- 原始跳转链接(示例):
https://gpu-pod6978c4fda2b3b8688426bd76-18789.web.gpu.csdn.net/chat?session=main - 删除
chat?session=main,追加?token=csdn - 最终 URL:
https://gpu-pod6978c4fda2b3b8688426bd76-18789.web.gpu.csdn.net/?token=csdn
成功登录后,右上角会显示 “Token: csdn”,且左下角模型选择器中可看到 “Local Qwen3 32B”。点击它,确保当前会话使用该模型。
5.2 发送第一条 function calling 请求
在聊天框中输入:
请查询2024年第一季度(1月-3月)各品类(category)的总销售额,并用柱状图展示。点击发送。你会看到 AI 的思考过程(非必需,但可开启 Debug 模式查看):
- 它识别出需调用
query_db,生成 SQL:SELECT category, SUM(amount) AS total FROM sales WHERE date BETWEEN '2024-01-01' AND '2024-03-31' GROUP BY category - Clawdbot 自动执行该 SQL,返回结果:
[{"category": "Electronics", "total": 1698.99}, {"category": "Home", "total": 264.49}] - AI 再次调用
plot_chart,传入上述数据,生成 base64 图片 - 最终回复中,不仅有文字总结,还内嵌一张清晰的柱状图!
小技巧:如果某次未触发工具,可追加一句“请务必使用提供的工具完成任务”,Qwen3:32B 对此类指令响应非常稳定。
6. 进阶技巧与避坑指南
6.1 如何让 SQL 更安全?加一层白名单校验
直接执行用户输入的 SQL 有风险。Clawdbot 支持在工具函数内部加校验逻辑。修改tools.py中的query_db:
def query_db(sql: str) -> List[Dict[str, Any]]: # 简单白名单:只允许 SELECT,禁止 DROP/UPDATE/INSERT if not sql.strip().upper().startswith("SELECT"): raise ValueError("Only SELECT statements are allowed.") # 禁止危险关键词 banned_keywords = ["DROP", "UPDATE", "INSERT", "DELETE", "PRAGMA", "ATTACH"] for kw in banned_keywords: if kw in sql.upper(): raise ValueError(f"Keyword '{kw}' is not allowed.") # 允许的表名白名单 allowed_tables = ["sales"] if not any(table in sql.lower() for table in allowed_tables): raise ValueError("Query must reference allowed tables only.") # ... 后续执行逻辑不变这样即使用户输入"DROP TABLE sales;",也会被拦截并返回明确错误。
6.2 多轮对话中保持上下文:如何让AI记住“刚才查的是Q1”?
Clawdbot 默认启用会话上下文(session context)。你只需确保每次提问都基于同一session=main(URL中已固定),Qwen3:32B 就能自然承接前序结果。例如:
- 第一轮:
请查Q1各品类销售额→ 返回数据 + 图表 - 第二轮:
把Q2的数据也加上,做对比图→ AI 会自动构造新 SQL 并调用plot_chart绘制双柱状图
无需额外配置,这是 Clawdbot + Qwen3 协同的原生能力。
6.3 性能优化:当响应变慢时,优先检查什么?
| 现象 | 可能原因 | 快速验证方式 |
|---|---|---|
| 首token延迟 > 3s | Ollama 未使用 GPU 加速 | ollama list查看gpus列是否为1;执行nvidia-smi确认显存占用 |
| 工具调用失败(报错无响应) | tools.py报异常未被捕获 | 查看 Clawdbot 终端日志,搜索ERROR关键词;临时在函数开头加print("DEBUG: entered") |
| 图表不显示(空白) | base64 字符串过长被截断 | 修改plot_chart中plt.savefig(..., dpi=80)降低分辨率;或改用 SVG 格式(需前端支持) |
7. 总结:你刚刚完成了一次生产级AI代理的闭环构建
回顾整个流程,你没有写一行 Flask 路由,没配一个 Nginx 反向代理,也没手动拼接 OpenAI 的tools参数。你只是:
✔ 用pipx install clawdbot启动了一个网关
✔ 编辑一个 JSON 文件,告诉它“我有个叫 qwen3:32b 的模型在本地跑着”
✔ 写了不到 50 行 Python,定义了两个函数:一个查数据库,一个画图
✔ 上传两个文件,点一下注册,就拥有了一个支持 function calling 的 AI 代理
这正是 Clawdbot 的设计哲学:把基础设施的复杂性封装掉,把开发者的时间还给业务逻辑本身。Qwen3:32B 则提供了足够强的底层能力——它不只是“能说人话”,而是真正理解“我要查什么”、“这个结果该怎么呈现”。
下一步,你可以轻松扩展:
- 把
sales.db换成 PostgreSQL 连接字符串,对接真实业务库; - 增加
send_email工具,让AI查完数据自动发日报; - 接入企业微信/飞书 Webhook,把图表推送到工作群;
- 用 Clawdbot 的监控面板,实时查看每个 agent 的调用成功率、平均延迟、错误类型分布。
AI 代理不该是实验室里的 Demo,而应是每天帮你省下两小时的同事。现在,它已经站在你的笔记本里,等你下一个问题。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。