掘金 人工智能 06月29日 22:27
Google AI Edge Function Calling: Android 端模型也能调用工具函数
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了端侧大模型应用开发中的核心概念——Function Calling(函数调用)。介绍了Google提供的AI Edge Function Calling SDK,以及其在Android/iOS等终端设备上的应用。通过对SDK的API、使用方法和Demo的分析,阐释了如何让端侧模型调用外部函数,实现复杂业务功能。文章还总结了Function Calling的优势,并探讨了其与MCP的关系。

🤖️ Function Calling(FC)使大模型能够调用外部函数、API或工具,从而扩展其能力,将模型从“只会聊天的模型”转变为“会用工具的智能体”。

🛠️ AI Edge Function Calling是Google为Android/iOS等终端设备提供的SDK,它简化了FC与端侧大语言模型交互的复杂性,开发者只需定义“工具”,模型即可理解并执行任务。

⚙️ FC的主要流程包括:定义函数声明、设置提示和输出格式、解析输出、检查响应并调用函数。SDK提供了FunctionDeclaration、ModelFormatter、InferenceBackend等API。

💡 示例Demo展示了FC在信息提取中的应用,通过语音输入,模型能识别并提取关键信息,例如姓名和生日,并将其与预定义的参数对应。

🔑 在Demo实现中,HammerFormatter将用户输入和系统指令打包成提示,GenerativeModel整合了推理后端、系统指令和工具集。函数声明通过FunctionDeclaration定义。

大家好,我是拭心。

上篇文章我们了解了如何在 Android 手机上实现 RAG。这篇文章我们来聊聊端上大模型应用开发的核心概念:Function Calling(函数调用能力,简写为 FC)。

Function Calling 本质上是让大模型在回答过程中,不直接给出最终答案,而是根据需求,调用外部函数/API/工具,拿到外部数据后再继续回答。

它把大模型从「只会聊天的模型」变成了「会用工具的智能体」。

AI Edge Function Calling 是 Google 为 Android/iOS 等终端设备提供的函数调用 SDK,它的出现让端上模型也能调用外部函数,实现一些复杂的业务功能。

一、了解 AI Edge Function Calling API

一般来说,Function Calling 主要包括这几步:

    定义函数声明:声明 LLM 可以调用的函数的结构和参数。设置提示和输出格式:将函数的数据结构转换为字符串以及将字符串转换为函数结构,以便 LLM 能够以适当的格式显示信息。解析输出:检测生成的响应是否包含函数调用,如果有将其解析为函数结构的数据类型,以便应用能够执行函数调用。检查响应:检测到输出有函数调用,使用适当的参数和结构化数据类型调用该函数。否则,它会返回自然语言文本。

AI Edge Function Calling SDK 提供相关的 API:

    函数定义,定义工具函数的名称和参数: FunctionDeclaration输入格式设置器: ModelFormatter,用于将函数声明转换为 LLM 所需的特定于模型的格式,并将其插入系统提示输出解析器: 还是 ModelFormatter,用于检测模型的输出是否表示函数调用,并将其解析为数据结构推理后端,封装 LLM Inference API 和 ModelFormatter: InferenceBackend,最终通过 LlmInferenceBackendSession 实现核心功能

二、如何使用

只看文档不容易理解,接下来我们通过 Google 的 Function Calling demo,来看看 FC API 如何使用。

2.1 demo 功能

demo 功能:在用户录音后,将录音数据转化为表格里的内容,提升信息录入效率。

在 demo 中,Function Calling 扮演着"信息提取器"的角色。

当用户通过语音输入"我叫拭心,生日是1990年5月12日"时,函数调用机制能识别出"拭心"是姓名,"1990年5月12日"是生日,并将其与预定义的 first_namelast_name等参数相对应。

2.2 通过 demo 的实现了解怎么使用

了解 demo 功能后,接下来我们通过 demo 的源码了解下 Function Calling SDK 怎么使用。

在 demo 项目中,整体流程包括这几步:

2.2.1 初始化

在初始化时,创建了 FormViewModel,在其中会创建 HammerFormatter(ModelFormatter 的一个实现):

```kotlin// in FormViewModel.createGenerativeModel()val formatter =    HammerFormatter(ModelFormatterOptions.builder().setAddPromptTemplate(true).build())```

ModelFormatter 是连接模型与函数调用逻辑的关键:

    请求格式化: 它将用户的文本输入、系统指令(systemInstruction)以及在 Tools.kt 中定义的可用工具(函数签名)打包成一个符合 Hammer 模型预期的提示(Prompt)。响应解析: 当模型返回结果时,格式化器会解析输出,判断它是一个普通的文本回答还是一个结构化的函数调用请求。

随后创建了 GenerativeModel,它是 Function Calling SDK 的核心入口,整合了推理后端、系统指令和工具集。

```kotlin// in FormViewModel.createGenerativeModel()val systemInstruction = Content.newBuilder()    .setRole("system")    .addParts(        Part.newBuilder()            .setText("This assistant will help you fill out a medical form.")    )    .build()val model = GenerativeModel(    llmInferenceBackend,    systemInstruction,    listOf(Tools.medicalFormTools).toMutableList() // 关键:定义模型可用的工具)```

2.2.2 函数注册

然后在 com/google/sample/fcdemo/functioncalling/Tools.kt 中声明了支持模型调用的函数列表:

val medicalFormTools: Tool = Tool.newBuilder()    .addFunctionDeclarations(        // 1. 姓名函数        FunctionDeclaration.newBuilder()            .setName("provide_name")            .setDescription("Records the user's first and last name.")            .setParameters(/* 参数定义 */)    )    .addFunctionDeclarations(        // 2. 生日函数        FunctionDeclaration.newBuilder()            .setName("provide_dob")            .setDescription("Records the user's date of birth.")            .setParameters(/* 参数定义 */)    )    .addFunctionDeclarations(        // 3. 人口统计函数        FunctionDeclaration.newBuilder()            .setName("provide_demographics")            .setDescription("Records the user's sex and marital status.")            .setParameters(/* 参数定义 */)    )    .addFunctionDeclarations(        // 4. 职业函数        FunctionDeclaration.newBuilder()            .setName("provide_occupation")            .setDescription("Records the user's occupation or job.")            .setParameters(/* 参数定义 */)    )    .addFunctionDeclarations(        // 5. 医疗历史函数        FunctionDeclaration.newBuilder()            .setName("update_medical_history")            .setDescription("Updates the user's medical history based on the conditions provided.")            .setParameters(/* 参数定义 */)    )    .build()

函数声明通过 FC SDK 的 FunctionDeclaration。

2.2.3 用户输入

当用户输入"我叫拭心,生日是1990年5月12日"时,HammerFormatter 会构建一个包含以下元素的完整提示:

LlmInferenceBackendSession#addSystemMessage:

public void addSystemMessage(Content systemInstruction, List<Tool> tools) {    this.systemInstruction = systemInstruction;    this.tools = new ArrayList(tools);    String systemMessage = this.formatter.formatSystemMessage(systemInstruction, tools);    this.llmInferenceSession.addQueryChunk(systemMessage);}

2.2.4 模型推理

模型接收到格式化后的提示后,会:

    理解用户意图:识别出用户想要填写表单匹配可用函数:从预定义的函数列表中找到最匹配的函数提取结构化数据:从自然语言中提取出具体的参数值生成函数调用:输出结构化的函数调用指令

当要调用函数时,模型返回的不是自然语言,而是结构化的函数调用对象:

{  "functionCall": {    "name": "provide_name",    "args": {      "fieldsMap": {        "first_name": {          "stringValue": "拭心"        },        "last_name": {          "stringValue": "<unknown>"        }      }    }  }}

2.2.5 函数调用

模型返回的响应包含在 Part 对象中,每个 Part 可能包含一个 functionCall

// 1.模型处理val response = chatSession!!.sendMessage(spokenText)// 2.从响应里找是否有函数调用response.getCandidates(0).content.partsList?.forEach { part ->    // extract the function from all the parts in the response    parts.forEach { part ->        part?.functionCall?.args?.fieldsMap?.forEach { (key, value) ->            value.stringValue?.let { stringValue ->                if (stringValue != "<unknown>") {                    //3.有函数调用,更新对应的 value                    when (key) {                        "first_name" -> _firstName.value = value.stringValue                        "last_name" -> _lastName.value = value.stringValue                        "occupation" -> _occupation.value = value.stringValue                        "sex" -> _sex.value = value.stringValue                        "marital_status" -> _maritalStatus.value = value.stringValue                        "date_of_birth" -> _dob.value = value.stringValue                        "conditions" -> {                            val currentMap = _medicalConditionsMap.value.toMutableMap()                            value.listValue.valuesList.forEach { condition ->                                currentMap[condition.stringValue] = true                            }                            _medicalConditionsMap.value = currentMap                        }                        else -> {                            throw Exception("Unknown function: $key value: $value")                        }                    }                }            }        }    }}

三、总结

好了,这就是 Google AI Edge Function Calling SDK 的相关介绍,它极大地简化 FC 与端侧大语言模型交互的复杂性,开发者无需手动进行复杂的提示工程和响应解析,只需定义好自己的"工具",即可让 AI 理解并执行任务,专注于应用的核心业务逻辑。

更多详细信息,请参阅 官方 Android 函数调用指南

PS:记录一个容易混淆的问题,MCP 和 Function Calling 的关系?目前我的理解:

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Function Calling AI Edge 大模型 端侧应用 SDK
相关文章