函数调用是指将大语言模型(LLM)可靠地连接到外部工具,以实现有效的工具使用和与外部API的交互。
大型语言模型(LLM)如 Llama、Mistral 或 GPT 模型经过微调,能够检测到何时需要调用函数,并输出包含调用函数所需参数的 JSON。通过函数调用所调用的函数将在您的 AI 应用程序中充当工具,并且您可以在单个请求中定义多个函数。
函数调用是构建基于大语言模型的聊天机器人或代理的重要能力,这些机器人或代理需要为大语言模型检索上下文或通过将自然语言转换为API调用来与外部工具交互。
功能调用使开发人员能够创建:
currency_converter(source_currency: string 'USD', target_currency: string 'TRY', amount: decimal '1000', when: datetime 'getdate()')
的函数调用。看来最近随着生成式人工智能出现的功能调用特性,可以逐渐应用于产品环境中。当我们查看伯克利功能调用排行榜时,你会发现大型语言模型能够以90%的成功率成功完成这一任务。
你可以轻松地在 watsonx.ai 环境中使用诸如 Mistral、Llama 和 Granite 在 Leaderboard 中的成功模型架构。以下我将一步步展示如何使用 watsonx.ai 提供端到端的解决方案。
一种证明有效的大规模语言模型幻觉结果的技术是检索增强生成,或称为 RAG。RAG 可以使用一个接收器来搜索外部数据,在将提示发送给生成器(即 LLM)之前,用绑定来丰富提示。
关于RAG和Function Calling之间的关系,如果一个使用RAG方法的场景需要从外部环境中实时或当前的数据提供者获取数据,在将接收者通过向量相似性搜索找到的上下文发送到LLM模型之前,会创建一个服务来通过上下文功能调用来查询外部提供者的数据。这样,包含数据的上下文与实时和最新的外部数据结合,使其更加丰富和实用。
例如;你可以依赖大型语言模型(LLM)的能力,从向量数据库中构建绑定,在你的检索增强生成(RAG)应用程序中,从实时数据(如股票价格、订单跟踪、航班模式或库存管理)运行绑定性能的功能。这种集成的RAG及其功能范围的目的是通过现有数据源或实时API的绑定(使LLM能够访问正确的信息)来支持请求。
具有调用选项能力的LLM使AI工具能够自主执行某些任务。例如,这些能力使LLM能够通过熟悉其他API和系统的功能,自动化涉及数据检索、处理和分析的复杂工作流程。
以下是一些可以从大型语言模型(LLM)的功能调用能力中受益的用例列表:
在本指南中,我们将演示如何使用 watsonx.ai 平台提示 Mistral-Large-2 和其他第三方模型执行不同用例的功能调用。
首先,我们必须详细定义我们想要调用的json对象。函数的描述参数在确定从所有定义的函数中选择哪个LLM模型时起着关键作用。在这里编写详细且可区分的描述非常重要。之后,当LLM在所有函数中调用此函数时,它会通过查看描述字段并使用类似零样本分类的方法来确定应该运行哪个函数。
此外,参数区域中每个参数的描述部分解释了如何找到正确的参数。为了做到这一点,LLM 可以通过使用实体提取方法,轻松地在传入的自然语言问题中找到诸如日期、数字、文本、地点、时间、金钱、人等对象,并将它们与正确的参数匹配。
通过这种方式,LLM 不仅能够利用零样本分类确定从功能列表中调用哪个函数,还能借助实体提取功能自动从输入的查询句子中提取所需的参数并将其设置为变量。
{ "type": "function", "function": { "name": "finance_service", "description": "财务顾问API提供所有金融需求和信息,包括金融指令、国际金融状态、资金交易、贷款、借方、银行操作等,您可以在该API中找到金融领域的所有内容", "parameters": { "type": "object", "properties": { "startdate": { "type": "string", "description": "请求的交易开始日期或时间,格式为dd-MM-yyyy,这是一个必需参数,您必须找到并返回开始日期值。如果查询中不包含任何开始日期,您可以将开始日期设置为01-01-2024", }, "enddate": { "type": "string", "description": "请求的交易结束日期或时间,格式为dd-MM-yyyy,这是一个必需参数,您必须找到并返回结束日期值。如果查询中不包含任何结束日期,您可以将结束日期设置为31-12-2024", }, }, "required": ["startdate"], "required": ["enddate"] }, }, }
在下一步中,我们将通过 ibm watsonx.ai-langchain SDK 访问平台,并为此需要从云环境中提供的参数,例如域名 URL、API 密钥、项目 ID 等。在从 IBM watsonx.ai 环境获取这些参数后,我们就可以在推理操作中使用 watsonx.ai 中的所有模型。
在这个场景中,我们将使用 mistral-large-2 模型来执行函数调用和实体提取操作。
def 工具调用(self, categories, query) -> str: response = "" categories = categories api_key=self.watsonx_ai_api_key 名称到函数 = { 'financial-advisor': functools.partial(self.get_finance_advice), } messages = [ ChatMessage(role="user", content=query) ] from langchain_ibm import WatsonxLLM 参数 = { "decoding_method": "sample", "max_new_tokens": 400, "min_new_tokens": 1, "temperature": 0.0, "top_k": 20, "top_p": 1, } 客户端 = WatsonxLLM( model_id="mistralai/mistral-large-latest", url="<<cloud-watsonx.ai-base-url", project_id="<<watsonx.ai-project-id>>", apikey= api_key, params=参数, ) response = 客户端.chat(messages=messages, tools=self.tools, tool_choice="auto") messages.append(response.choices[0].message) 工具调用 = response.choices[0].message.tool_calls[0] 函数名称 = 工具调用.function.name 函数参数 = json.loads(工具调用.function.arguments) if self.validate_input(函数参数): print("\n函数名称: ", 函数名称, "\n函数参数: ", 函数参数) 函数结果 = 名称到函数[函数名称](https://medium.com/**函数参数) messages.append(ChatMessage(role="tool", name=函数名称, content=函数结果["content"], tool_call_id=工具调用.id)) response = 客户端.chat(model=model, messages=messages) else: raise ValueError("无效的输入参数") return response.choices[0].message.content
准备的提示如下。这是我们的提示,旨在找出相关问题想要表达的内容及其所属的类别。在收到相关值后,此提示会查询第三方机构的API,并返回机构提供的类别值,这些值将被存储,用于最终发送给机构的查询。
def prompt_generator(self, question, table) -> str: prompt_category_detection = """你是一名财务专家,任务是分析以下财务句子,并从指定的表格中选择最相关的标题。请按照以下步骤操作: **检索相关数据**:从识别的表格中找到与句子内容最匹配的财务主题和财务类别。 **财务句子:** "{question}" **字典:** {table} **说明:** - 从字典中确定正确的表格。 - 使用该表格找到与财务句子最相关的财务主题和财务类别值。 - 确保检索到的值是与句子内容的最佳匹配。 **结论:** 请以以下格式提供结果,仅返回以下信息,不要添加任何其他单词或句子,仅以JSON对象格式给出答案,仅以以下格式返回答案,不要使用其他格式: {{"category": "找到的类别", "id": 类别_id}} """ return prompt_category_detection.format(question=question, table=table)
类别服务调用如下进行,并将响应存储在变量中,以便发送POST请求到主服务。
def _解析用户查询(self, user_query: str) -> str: category_prompt = self.prompt_generator(question=user_query, table=self.categories) category_response = self.model.invoke(category_prompt) category_json = json.loads(category_response.content) print("从LLM零样本分类中找到的值:", category_json) category_id = category_json["id"] return category_json.content
使用从第一个服务返回的类别以及通过实体提取从问题中提取的开始日期和结束日期参数,LLM 自动调用以下函数。在进行此调用时,相关函数在代码的其他地方不会被调用。
def 获取财务建议(self, startdate, enddate) -> Dict: full_category_codes = "" for cin self.category_codes: full_category_codes += c["code"] + "-" base_url = '<<third-party-api-base-uri' + full_category_codes +'&startDate='+ startdate +'&endDate='+ enddate response = requests.get(base_url+'&type=json', headers=headers) print(response.content) return { "状态码": response.status_code, "内容": response.content }
该基于生成AI的金融推荐系统的解决方案架构非常成功地从端到端运行,其架构如下。系统通过界面或API接收用户的查询,并通过SDK将其发送到后台的watsonx.ai环境中。之后,watsonx.ai使用其基础模型库中的Mistral-Large-2模型查询传入的查询,并确定将在第4步中使用的功能。然后,在第5步中确定的功能内执行实体提取,找到并发送时间相关的参数(如开始和结束日期)到变量。在这里,大型语言模型使用零样本分类功能来找到正确的功能,然后使用实体提取从自然语言查询句子中找到正确的参数。
在下一步中,LLM 会调用嵌入在 watsonx.ai 中的目录来调用正确的函数,并通过 Python 启动对该函数的调用。在调用过程中,还需要进行另一次分类过程来查找相关的目录信息。为此,我们通过 SDK 将 gpt-4o-mini 模型集成到 watsonx.ai 中,并利用其在表格数据上的分类能力。我们在这里使用 gpt-4o-mini 的原因是,与其他模型架构(如 mistral 和 llama)相比,该模型在表格数据的零样本分类等任务中更为成功,并且始终能给出相同的结果。另一个原因是展示 watsonx.ai 环境可以通过 SDK 访问不同云或其它环境中的模型,而不仅仅是其自身的模型服务器中的模型。
在完成所有这些工作的同时,我们充分利用了langchain在每一步中的能力。在LLM推理操作(如2、3和4所示)中对表格数据进行分类操作后,现在使用watsonx.ai及其所有获取的参数调用了服务。
服务返回的值。在最后一步,它被发送回watsonx.ai中的mistral-large-2模型,并要求该模型结合从机构接收的服务数据,生成对问题的适当回答。 如下所示,所有过程的分步输出和watsonx.ai生成的LLM回答都列出来了。
最后,通过执行文本生成来完成整个过程。通过发送5个独立的推理请求到大语言模型,满足了3个不同任务(零样本分类、实体提取、文本生成)在两个不同模型中的需求。
你可以这样理解系统和模型的输出。
测试结果:
问题1:2024年5月英镑对土耳其里拉的最高汇率是多少?
来自LLM分类和实体提取的分类结果:
{'类别': '汇率', 'id': 35} [{'名称': '(GBP) 英镑 (买入外币价格)', '代码': 'EN-POUND-BUY'}, {'名称': '(GBP) 英镑 (外币卖出)', '代码': 'EN-POUND-SALE'}]
函数参数,LLM 使用实体提取功能获取这些参数:
{'startdate': '2024-01-05', 'enddate': '2024-05-31'}
文本生成结果来自LLM,在这一步中,LLM使用API响应体中的值
来自Watsonx.ai的回答 = “2024年5月,英镑兑土耳其里拉的最高汇率为41.2021 TRY”
问题2:根据最新数据,非居民投资组合中的股票和债务证券的年度变化率是多少?
来自LLM分类和实体提取的分类结果:
{'类别': '国际投资头寸', 'id': 36} {'名称': '境外居民投资组合中的股票和债务证券', '代码': 'stock_and_debt_external_citizens'} [{'名称': '海外银行存款', '代码': 'bank_overseas_deposits'}, {'名称': '银行外汇存款账户', '代码': 'Bank_Foreign_Exchange_Deposits'}]
函数参数,LLM 使用实体提取功能获取这些参数:
{'startdate': '2024-01-01', 'enddate': '2024-12-31'}
从LLM生成的文本结果,在这一步中,LLM使用API响应体中的值
来自Watsonx.ai的回答 = “非居民投资组合中的股票和债务证券的年度变化率为5.7%。”
问题3:2023年在航空和住宿业通过借记卡和信用卡支出的总额占借记卡和信用卡总支出的百分比是多少?
来自LLM分类和实体提取的分类结果:
{'分类': '银行和信用卡部门支出统计', 'id': 77} {'名称': '借记卡和信用卡消费金额', '代码': 'debit_credit_sp'} [{'名称': '航空公司', '代码': 'trx-airlines-fnc'}, {'名称': '住宿', '代码': 'trx-accom-fnc'}]
函数参数,LLM 使用实体提取功能获取这些参数:
{'startdate': '2023-01-01', 'enddate': '2023-12-31'}
文本生成结果来自LLM,在这一步中,LLM使用API响应体中的值
来自Watsonx.ai的回答 = “在2023年,借记卡和信用卡总支出中有10.5%用于航空和住宿行业。总支出金额为199,384,100土耳其里拉。”
此外,我们的 Mistral 官方网站上还提供了一个详细讲解如何使用我们在 watsonx.ai 中使用的 mistral-large-2 模型进行函数调用的培训视频。我们所做的就是通过 langchain 设置服务调用或 RAG 结构,使用 watsonx.ai 中的 Mistral 模型。
我也想感谢所有我的队友,Seray Boynuyoğun,Ceyda Hamurcu,Bengü Sanem Pazvant,Merve Özmen,Yunus Emre Emik 和 Ahmet Sait Çelik,他们作为IBM土耳其客户端工程团队的一员,为这项工作做出了贡献。没有团队是无法做到这一点的。一个团队!!