大模型和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 函数) 来精确处理表格,再把工具返回的结果整理成自然语言回答。

描述:有一个本周饮品销量小表,希望大模型输出按饮品汇总销量的列表,以及销量最高的饮品是什么,以及哪个门店销量最高

典型流程:

scss 复制代码
用户问:"按饮品汇总销量。"
模型看到可用的函数列表,比如 compute_groupby_sum(column, group_by)。
模型不自己计算,而是输出一个函数调用指令:compute_groupby_sum(column="销量_杯", group_by="饮品")。
你的程序拦截这个指令,让 Python 后端实际执行 df.groupby("饮品")["销量_杯"].sum(),拿到精确结果 {"美式":42, "拿铁":18, "橙汁":12}。
你的程序把这个结果送回模型,模型再组织成一句人话:"美式共卖出42杯,拿铁18杯,橙汁12杯。"

代码示例

python 复制代码
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",更直观地理解整个实现流程。

相关推荐
mldong6 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排7 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60617 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角9 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!9 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰9 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi10 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen11 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马12 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒12 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端