如何利用 Function Calling 结合本地数据库实现动态报表生成
把大模型当成一个「自然语言转 SQL」的翻译官其实太浪费了,真正的正确姿势是把数据库查询能力封装成 Tool,让 LLM 通过 Function Calling 自主决定调用哪个接口。我最近在做一个内部财务报表系统,通过这种方式实现了用户直接问「对比上季度,哪个产品线的毛利下滑最严重」,AI 就能自动生成分析报表。
最核心的坑在于:绝对不要让 AI 直接写 SQL 语句并执行,否则一旦遇到复杂的 Join 或者慢查询,数据库直接宕机。我采取的方案是定义一套标准化的「查询原语」。
定义 Function 的 Schema 时,参数要极其具体。比如我定义了一个 get_sales_report 函数:
{
"name": "get_sales_report",
"description": "获取销售额报表,支持按维度分组和时间筛选",
"parameters": {
"type": "object",
"properties": {
"dimensions": {
"type": "array",
"items": { "type": "string", "enum": ["product_line", "region", "sales_rep"] },
"description": "统计维度"
},
"time_range": {
"type": "string",
"description": "时间范围,格式为 YYYY-MM-DD to YYYY-MM-DD"
},
"metric": {
"type": "string",
"enum": ["revenue", "profit", "order_count"],
"description": "统计指标"
}
},
"required": ["dimensions", "time_range", "metric"]
}
}在后端实现层,我用 Python 写了一个映射层,将这些参数转化为预定义的 SQL 模板。这样既保证了安全,又提升了执行效率。
效率提升的关键点:
上下文注入。在 System Prompt 中给 AI 一份简易的「数据字典」,告诉它哪些维度是关联的。比如:当前可用维度:product_line(产品线), region(区域)。注意:毛利分析必须使用 profit 指标。如果不加这个,AI 经常会幻想出一些数据库里根本不存在的字段名。
多步推理链。复杂的报表往往需要多次调用。比如用户问「谁是上季度表现最差的销售」,AI 的执行路径应该是:get_sales_report(metric='revenue', dimensions=['sales_rep']) → 获取结果列表 → 在内存中排序找到最小值 → 输出结论。
踩过的坑:
参数类型不匹配是最高频的问题。尤其是日期格式,LLM 经常把「上个月」直接传给函数,导致 SQL 报错。我在中间层加了一个简单的日期解析函数,强制将自然语言日期转换为 YYYY-MM-DD。
代码逻辑实现片段:
def handle_tool_call(tool_call):
# 将 AI 返回的参数映射到预设 SQL
params = tool_call.arguments
sql_template = "SELECT {dim}, SUM({met}) FROM sales WHERE date BETWEEN '{start}' AND '{end}' GROUP BY {dim}"
# 安全过滤,防止注入
safe_dim = params['dimensions'][0] if params['dimensions'][0] in ALLOWED_DIMS else 'id'
query = sql_template.format(
dim=safe_dim,
met=params['metric'],
start=params['time_range'].split(' to ')[0],
end=params['time_range'].split(' to ')[1]
)
return db.execute(query)这种方案比单纯的 Text-to-SQL 稳定得多,因为你把控制权握在了自己手里,AI 只负责调度。
免费 AI 工具箱 · 全部完全免费
全部回复 (0)
还没有回复,来发第一条吧!
