大模型和function calling分别是如何工作的
以一个表处理为例:
github地址:github.com/YueJingGe/p…
用大模型处理表格
描述:有一个本周饮品销量小表,希望大模型输出按饮品汇总销量的列表,以及销量最高的饮品是什么
代码示例+运行结果
![]()
核心思想
当你把表格 用 df.to_string() 转成文本,然后放进 prompt 里时,大模型(如通义千问、GPT-4)会做这几步:
- 1、阅读理解:识别出这是一个三列表格,理解列名含义(“饮品”“销量_杯”“门店”)。
- 2、信息提取:逐行读取数据,记住每行对应关系。
- 3、简单计算:将“美式”的两行销量 30 和 12 相加,得到 42;将“拿铁”的 18 单独作为总和;将“橙汁”的 12 作为总和。
- 4、格式组织:按要求的格式输出“美式:42,拿铁:18,橙汁:12”。 这些能力完全来自大模型自身的训练——它在海量数据中学到了如何理解文本表格、如何进行基本的聚合计算(求和、计数等)、如何比较大小。你不需要额外实现任何逻辑,只要把表格文本喂给模型,它就能尝试回答。
技术架构图
![]()
局限性
虽然模型能处理简单的表格问答,但有以下问题:
- 1、计算错误:当表格行数多、数字复杂(如带小数、需加权平均),或者需要多步运算(先分组再排序再筛选),模型容易算错或遗漏。
- 2、上下文长度:表格太大(比如1000行),放进 prompt 可能超过模型的 token 限制,或导致注意力分散、遗漏关键信息。
- 3、不确定性:同一个表格问同一个问题,模型可能给出略有差异的答案(因为生成有随机性)。
- 4、无法执行复杂逻辑:比如“找出销量最高的门店,再列出该门店销量前两名的饮品”,这类需要多步条件筛选和排序的任务,模型往往做不好。
Function Calling + 大模型处理表
首先,Function calling(也称工具调用)不是让模型直接分析表格,而是让模型决定去调用一个外部工具(比如写好的 Python 函数) 来精确处理表格,再把工具返回的结果整理成自然语言回答。
描述:有一个本周饮品销量小表,希望大模型输出按饮品汇总销量的列表,以及销量最高的饮品是什么,以及哪个门店销量最高
典型流程:
用户问:“按饮品汇总销量。”
模型看到可用的函数列表,比如 compute_groupby_sum(column, group_by)。
模型不自己计算,而是输出一个函数调用指令:compute_groupby_sum(column="销量_杯", group_by="饮品")。
你的程序拦截这个指令,让 Python 后端实际执行 df.groupby("饮品")["销量_杯"].sum(),拿到精确结果 {"美式":42, "拿铁":18, "橙汁":12}。
你的程序把这个结果送回模型,模型再组织成一句人话:“美式共卖出42杯,拿铁18杯,橙汁12杯。”
代码示例
import os
import json
import pandas as pd
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(
api_key=os.getenv('DASHSCOPE_API_KEY'),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# ---------- 定义真实的数据查询函数(后端执行) ----------
# 使用 pandas 创建数据表
df = pd.DataFrame({
"饮品": ["美式", "拿铁", "橙汁", "美式"],
"销量_杯": [30, 18, 12, 12],
"门店": ["A店", "A店", "B店", "B店"],
})
def get_sales_summary(by: str = "饮品"):
"""
获取销量汇总数据。
by: 分组依据,目前支持 "饮品" 或 "门店"
"""
if by == "饮品":
grouped = df.groupby("饮品")["销量_杯"].sum().reset_index()
grouped = grouped.sort_values("销量_杯", ascending=False)
# 转为字典列表,方便模型阅读
result = grouped.to_dict(orient="records")
elif by == "门店":
grouped = df.groupby("门店")["销量_杯"].sum().reset_index()
grouped = grouped.sort_values("销量_杯", ascending=False)
result = grouped.to_dict(orient="records")
else:
result = {"error": f"不支持的聚合方式: {by}"}
return json.dumps(result, ensure_ascii=False)
def get_top_sales(by: str = "饮品"):
"""获取销量冠军"""
if by == "饮品":
grouped = df.groupby("饮品")["销量_杯"].sum()
top_item = grouped.idxmax()
top_value = int(grouped.max())
return json.dumps({"冠军": top_item, "销量": top_value}, ensure_ascii=False)
elif by == "门店":
grouped = df.groupby("门店")["销量_杯"].sum()
top_item = grouped.idxmax()
top_value = int(grouped.max())
return json.dumps({"冠军": top_item, "销量": top_value}, ensure_ascii=False)
else:
return json.dumps({"error": f"不支持的冠军查询: {by}"})
# ---------- 定义工具描述(给大模型看的说明书) ----------
tools = [
{
"type": "function",
"function": {
"name": "get_sales_summary",
"description": "按饮品或门店获取销量汇总,返回排序后的列表",
"parameters": {
"type": "object",
"properties": {
"by": {
"type": "string",
"enum": ["饮品", "门店"],
"description": "分组维度,例如'饮品'或'门店'"
}
},
"required": ["by"]
}
}
},
{
"type": "function",
"function": {
"name": "get_top_sales",
"description": "获取销量冠军(销量最高的饮品或门店)",
"parameters": {
"type": "object",
"properties": {
"by": {
"type": "string",
"enum": ["饮品", "门店"],
"description": "冠军类型,例如'饮品'或'门店'"
}
},
"required": ["by"]
}
}
}
]
# ---------- 主对话循环 ----------
def ask_with_function_calling(user_question):
messages = [{"role": "user", "content": user_question}]
# 第一次调用:让模型判断是否需要调用函数
first_response = client.chat.completions.create(
model="qwen-plus", # 或 qwen-turbo
messages=messages,
tools=tools,
tool_choice="auto",
)
response_message = first_response.choices[0].message
messages.append(response_message)
# 模型要求调用函数吗?
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f"🔧 模型调用: {func_name}, 参数: {func_args}")
# 执行真实的 Python 函数
if func_name == "get_sales_summary":
result = get_sales_summary(**func_args)
elif func_name == "get_top_sales":
result = get_top_sales(**func_args)
else:
result = json.dumps({"error": "未知函数"})
# 将工具结果加入对话
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result,
})
# 第二次调用:模型根据工具结果生成最终回答
second_response = client.chat.completions.create(
model="qwen-plus",
messages=messages,
)
final_answer = second_response.choices[0].message.content
return final_answer
else:
# 没有工具调用,直接返回模型回答
return response_message.content
# ---------- 运行示例 ----------
if __name__ == "__main__":
# 问题1:按饮品汇总销量
q1 = "按饮品汇总销量,并告诉我销量最高的饮品是什么"
print(f"🙋 用户: {q1}")
ans1 = ask_with_function_calling(q1)
print(f"🤖 AI: {ans1}\n")
# 问题2:销量冠军门店
q2 = "哪个门店的销量最高?"
print(f"🙋 用户: {q2}")
ans2 = ask_with_function_calling(q2)
print(f"🤖 AI: {ans2}\n")
运行结果:
![]()
核心思想
核心思想就是:
1、你给模型预定义一组函数,告诉模型这些函数能做什么。
2、用户问自然语言问题,比如“按饮品汇总销量,然后自然地说出来”。
3、大模型自己决定该不该调用函数、调用哪个函数、传什么参数。
4、模型返回的不是最终答案,而是一个函数调用指令(例如 get_sales_summary(by='drink'))。
5、你的代码收到这个指令后,实际去执行 pandas 计算(或查数据库、调API等),然后把精确的计算结果再发回给模型。
6、模型根据结果生成最终的自然语言回答。
整个过程中,模型在主动决策“我需要调用工具来帮忙”,而不仅仅是接收现成数据。
技术架构图
![]()
总结
不用 Function Calling 的时候主要是依赖大模型本身的语言理解和推理能力,适合你完全清楚要算什么的场景,代码简单高效。
用 Function Calling是作为一种“增强手段”来提升准确性和能力上限,适合搭建对话式数据分析助手,用户可以随意提问,模型自动选择合适的函数去执行。
深入学习
Function Calling 官方资料:
阿里云百炼平台:搜索“阿里云百炼 Function Call”,参考官方文档。
社区博客:搜索“超实用!用 FunctionCall 实现快递 AI 助手”,了解用它构建真实 AI 助手的详细步骤。
CSDN 博客:搜索“通义千问的 Function Call”,更直观地理解整个实现流程。