前言
AI智能体是指具备一定自主性、能感知环境并通过智能决策执行特定任务的软件或硬件实体。它结合了人工智能技术(如机器学习、自然语言处理、计算机视觉等),能够独立或协作完成目标。基于大语言模型(LLM)的Function Calling可以令智能体实现有效的工具使用和与外部API的交互。
并非所有的LLM模型都支持Function Calling。支持Function Calling的模型(如gpt-4,qwen-plus等)能够检测何时需要调用函数,并输出调用函数的函数名和所需参数的JSON格式结构化数据。
Function Calling提高了输出稳定性,并简化了提示工程的复杂程度。对于不支持Function Calling的模型,可通过ReACT的相对较为复杂的提示词工程,要求模型返回特定格式的响应,以便区分不同的阶段(思考、行动、观察)。
Function Calling主要有两个用途:
- 获取数据:例如根据关键字从知识库检索内容、通过特定API接口获取业务数据
- 执行行动:例如通过API接口修改业务状态数据、执行预定业务操作
本文包含如下内容:
- 详细介绍Function Calling工具调用流程和涉及的交互消息
- 手搓Agent代码实现Function Calling工具调用
Function Calling工具调用流程和交互消息
我们以查询北京和广州天气为例,LLM采用通义千问qwen-plus。查询天气的流程如下图:
1. 发起查询请求
向LLM发起查询时,messages列表只有一条消息(role为user, content为用户查询内容)。另外,还需要带上tools定义。
tools定义包含如下内容:
- name: 函数名
- description: 函数描述
- parameters: 参数定义
本例中,定义了函数get_weather(location)。
我们用curl发起POST请求,body的JSON结构可参考https://platform.openai.com/docs/api-reference/chat/create
复制2. LLM返回tool_calls获取北京天气
LLM经过推理,发现需要调用函数获取北京天气,回复的消息带上tool_calls信息。
本例中,需要调用函数get_weather,参数名为location, 参数值为北京。
完整的JSON响应如下:
复制3. 处理函数调用获取北京天气
解析处理LLM的tool_calls获得函数名和参数列表,调用相应的API接口获得结果。
例如:通过http://weather.cma.cn/api/now/54511可获得北京的天气情况。
完整的JSON响应如下:
复制4. 把上下文信息以及函数调用结果发给LLM
发给LLM的messages列表有3条messages:
- 第1条role为user,是用户的输入
- 第2条role为assistant,是LLM的tool_calls响应get_weather('北京')
- 第3条role为tool,是工具调用get_weather('北京')的结果
5. LLM返回tool_calls获取广州天气
LLM经过推理,发现需要调用函数获取广州天气,回复的消息带上tool_calls信息。
本例中,需要调用函数get_weather,参数名为location, 参数值为广州。
完整的JSON响应如下:
复制6. 处理函数调用获取广州天气
解析处理LLM的tool_calls获得函数名和参数列表,调用相应的API接口获得结果。
例如:通过http://weather.cma.cn/api/now/59287可获得广州的天气情况。
完整的JSON响应如下:
复制7. 把上下文信息以及函数调用结果发给LLM
发给LLM的messages列表有5条messages:
- 第1条role为user,是用户的输入
- 第2条role为assistant,是LLM的tool_calls响应get_weather('北京')
- 第3条role为tool,是工具调用get_weather('北京')的结果
- 第4条role为assistant,是LLM的tool_calls响应get_weather('广州')
- 第5条role为tool,是工具调用get_weather('广州')的结果
8. LLM生成最终回复
LLM生成最终的回复:
复制完整的JSON响应如下:
复制手搓Agent代码实现Function Calling工具调用
1. 创建python环境
复制2. 设置API Key
创建.env,.env内容如下(注意修改OPENAI_API_KEY为您的key)
复制把.env添加到.gitignore
3. 实现Agent代码
基于openai sdk实现agent的主体代码逻辑是:在允许的迭代次数范围内,循环处理,发起chat completions直至没有tool_calls, 迭代结束,输出结果。
伪代码:
复制完整的main.py代码如下:
复制运行代码:uv run .\main.py
输出日志如下:
复制