AI代码开发宝库系列:Function Call

复制代码

手把手教你用Python实现AI多功能助手:一个脚本搞定天气、股票、计算器和翻译!

前言:让AI变得更强大

大家好!今天我要分享一个超级实用的AI项目------用Python打造一个能同时处理天气查询、股票价格、数学计算和文本翻译的AI助手!你没听错,一个脚本就能搞定这么多功能!

传统的AI只能聊天,但通过Function Calling技术,我们可以让AI真正"动起来",调用各种工具为我们服务。这篇文章我会用最通俗的语言,带你一步步实现这个强大的AI助手。

项目效果展示

先来看看我们的AI助手能做什么:

  • 查询北京天气:温度、天气状况一键获取

  • 查看AAPL股票:实时价格随时掌握

  • 计算数学题:2的10次方是多少?AI秒算!

  • 翻译文本:中文"你好"翻译成英文"Hello"

所有这些功能,AI都能智能识别并准确调用相应的工具!

核心技术解析

什么是Function Calling?

简单来说,Function Calling就是让AI在对话中能够"调用函数"。当用户问"北京天气怎么样?"时,AI会自动识别这是天气查询需求,然后调用我们写好的天气函数来获取真实数据。

为什么用functions而不是tools?

在dashscope中,有两种方式定义可调用的函数:

  1. functions:更简洁的定义方式,适合大多数场景

  2. tools:更复杂的定义方式,功能更强大但使用稍复杂

我们选择使用更简单的functions方式。

代码实现详解

第一步:准备基础函数

我们先定义四个核心函数:

复制代码
# 天气查询函数
def get_current_weather(location, unit="摄氏度"):
    # 实现天气查询逻辑...
​
# 股票查询函数
def get_stock_price(symbol):
    # 实现股票查询逻辑...
​
# 计算器函数
def calculate(expression):
    # 实现数学计算逻辑...
​
# 翻译函数
def translate_text(text, target_language="en"):
    # 实现文本翻译逻辑...

第二步:定义函数描述

为了让AI知道每个函数的用途,我们需要详细描述:

复制代码
functions = [
    {
        "name": "get_current_weather",
        "description": "获取指定地点的当前天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "地点名称,如:北京、上海等"
                },
                "unit": {
                    "type": "string",
                    "description": "温度单位",
                    "enum": ["摄氏度", "华氏度"]
                }
            },
            "required": ["location"]
        }
    },
    # ... 其他函数定义
]

第三步:建立函数映射

为了让AI调用函数时能找到对应的实现,我们建立映射关系:

复制代码
function_map = {
    "get_current_weather": get_current_weather,
    "get_stock_price": get_stock_price,
    "calculate": calculate,
    "translate_text": translate_text
}

第四步:实现AI调用逻辑

最关键的部分是让AI能够智能调用函数:

复制代码
# 当AI决定调用函数时
if hasattr(message, 'function_call') and message.function_call:
    function_call = message.function_call
    fn_name = function_call['name']
    fn_arguments = function_call['arguments']
    
    # 通过映射找到并调用对应函数
    if fn_name in function_map:
        function_response = function_map[fn_name](**arguments_json)

完整运行代码

复制代码
#!/usr/bin/env python
# coding: utf-8
​
import json
import os
import random
import dashscope
​
# 设置API密钥
api_key = os.environ.get('DASHSCOPE_API_KEY')
if api_key:
    dashscope.api_key = api_key
​
# 四个核心功能函数
def get_current_weather(location, unit="摄氏度"):
    """获取指定地点的当前天气"""
    temperature = random.randint(20, 35)
    weather_info = {
        "地点": location,
        "温度": temperature,
        "单位": unit,
        "天气": "晴天",
        "风力": "微风"
    }
    return json.dumps(weather_info, ensure_ascii=False)
​
def get_stock_price(symbol):
    """获取指定股票代码的当前价格"""
    price = round(random.uniform(100, 500), 2)
    stock_info = {
        "股票代码": symbol.upper(),
        "当前价格": price,
        "货币单位": "USD"
    }
    return json.dumps(stock_info, ensure_ascii=False)
​
def calculate(expression):
    """执行数学计算"""
    try:
        result = eval(expression)
        return json.dumps({"表达式": expression, "计算结果": result}, ensure_ascii=False)
    except Exception as e:
        return json.dumps({"表达式": expression, "错误": str(e)}, ensure_ascii=False)
​
def translate_text(text, target_language="en"):
    """翻译文本到目标语言"""
    translations = {"你好": "Hello", "谢谢": "Thank you"}
    translated = translations.get(text, f"[Translated] {text}")
    return json.dumps({"原文": text, "译文": translated}, ensure_ascii=False)
​
# 函数映射字典
function_map = {
    "get_current_weather": get_current_weather,
    "get_stock_price": get_stock_price,
    "calculate": calculate,
    "translate_text": translate_text
}
​
# 函数定义
functions = [
    {
        "name": "get_current_weather",
        "description": "获取指定地点的当前天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "地点名称"},
                "unit": {"type": "string", "enum": ["摄氏度", "华氏度"]}
            },
            "required": ["location"]
        }
    },
    {
        "name": "get_stock_price",
        "description": "获取指定股票代码的当前价格",
        "parameters": {
            "type": "object",
            "properties": {"symbol": {"type": "string", "description": "股票代码"}},
            "required": ["symbol"]
        }
    },
    {
        "name": "calculate",
        "description": "执行数学计算表达式",
        "parameters": {
            "type": "object",
            "properties": {"expression": {"type": "string", "description": "数学表达式"}},
            "required": ["expression"]
        }
    },
    {
        "name": "translate_text",
        "description": "将文本翻译成目标语言",
        "parameters": {
            "type": "object",
            "properties": {
                "text": {"type": "string", "description": "需要翻译的文本"},
                "target_language": {"type": "string", "default": "en"}
            },
            "required": ["text"]
        }
    }
]
​
# 调用AI模型
def get_response(messages):
    try:
        response = dashscope.Generation.call(
            model='qwen-max',
            messages=messages,
            functions=functions,
            result_format='message'
        )
        return response
    except Exception as e:
        print(f"API调用出错: {str(e)}")
        return None
​
# 主函数
def run_conversation():
    messages = [
        {"role": "system", "content": "你是一个多功能助手"},
        {"role": "user", "content": "查询北京天气、AAPL股价、计算2的10次方、翻译'你好'"}
    ]
    
    for i in range(5):
        response = get_response(messages)
        if not response or not hasattr(response, 'output'):
            break
            
        message = response.output.choices[0].message
        messages.append(message)
        
        # 处理函数调用
        if hasattr(message, 'function_call') and message.function_call:
            function_call = message.function_call
            fn_name = function_call['name']
            arguments = json.loads(function_call['arguments'])
            
            if fn_name in function_map:
                function_response = function_map[fn_name](**arguments)
                messages.append({
                    "name": fn_name,
                    "role": "function",
                    "content": function_response
                })
        elif response.output.choices[0].finish_reason == 'stop':
            break
    
    return messages[-1].content if messages else "对话失败"
​
if __name__ == "__main__":
    result = run_conversation()
    print("最终结果:", result)

多函数调用代码执行流程详解

根据您提供的实际运行输出,我来详细说明multi_function_with_functions.py的执行流程:

1. 初始化阶段

复制代码

python

复制代码
`# 初始化对话
messages = [
    {"role": "system", "content": "你是一个多功能助手,可以帮助用户查询天气、股票价格,进行数学计算和文本翻译。"},
    {"role": "user", "content": "我想查询北京的天气,AAPL股票的价格,计算2的10次方,并将'你好'翻译成英文。"}
]`

系统首先建立初始对话消息,包含系统提示和用户请求。

2. 第一轮对话 - 天气查询

AI分析与函数调用决策

AI模型分析用户请求后,识别出第一个任务是查询北京天气,决定调用get_current_weather函数。

函数调用执行

复制代码
复制代码
`--- 对话轮次 1 --- 调用函数: get_current_weather 参数: {"location": "北京", "unit": "摄氏度"} 函数响应: {"地点": "北京", "温度": 25, "单位": "摄氏度", "天气": "晴天", "风力": "微风"}`
  1. 程序检测到message.function_call存在,提取函数名和参数
  2. 通过function_map找到对应的函数实现
  3. 调用get_current_weather函数并传入参数
  4. 函数返回天气信息,程序将结果以role="function"的形式添加到对话历史中

3. 第二轮对话 - 股票查询

AI继续处理剩余任务

AI识别出第二个任务是查询AAPL股票价格,调用get_stock_price函数。

函数调用执行

复制代码
复制代码
`--- 对话轮次 2 --- 调用函数: get_stock_price 参数: {"symbol": "AAPL"} 函数响应: {"股票代码": "AAPL", "当前价格": 169.73, "货币单位": "USD"}`

流程与第一轮相同,调用股票查询函数并返回结果。

4. 第三轮对话 - 数学计算

AI处理计算任务

AI识别出第三个任务是计算2的10次方,调用calculate函数。

函数调用执行

复制代码
复制代码
`--- 对话轮次 3 --- 调用函数: calculate 参数: {"expression": "2**10"} 函数响应: {"表达式": "2**10", "计算结果": 1024}`

5. 第四轮对话 - 文本翻译

AI处理翻译任务

AI识别出第四个任务是翻译文本,调用translate_text函数。

函数调用执行

复制代码
复制代码
`--- 对话轮次 4 --- 调用函数: translate_text 参数: {"text": "你好", "target_language": "en"} 函数响应: {"原文": "你好", "译文": "Hello", "目标语言": "en"}`

6. 第五轮对话 - 综合回答

AI生成最终回答

在收集完所有函数调用结果后,AI生成综合回答:

复制代码
复制代码
`--- 对话轮次 5 --- AI助手: 北京的当前天气是晴天,温度为25摄氏度,风力微风。  AAPL(苹果公司)的股票当前价格为169.73美元。  数学表达式2的10次方的结果是1024。  "你好"翻译成英文是"Hello"。 对话结束`

7. 对话历史输出

最后程序输出完整的对话历史:

复制代码
复制代码
`============================================================ 对话历史: [系统] 你是一个多功能助手,可以帮助用户查询天气、股票价格,进行数学计算和文本翻译。 [用户] 我想查询北京的天气,AAPL股票的价格,计算2的10次方,并将'你好'翻译成英文。 [助手]  [函数:get_current_weather] {"地点": "北京", "温度": 25, "单位": "摄氏度", "天气": "晴天", "风力": "微风"} [函数:get_stock_price] {"股票代码": "AAPL", "当前价格": 169.73, "货币单位": "USD"} [函数:calculate] {"表达式": "2**10", "计算结果": 1024} [函数:translate_text] {"原文": "你好", "译文": "Hello", "目标语言": "en"} [助手] 北京的当前天气是晴天,温度为25摄氏度,风力微风。  AAPL(苹果公司)的股票当前价格为169.73美元。  数学表达式2的10次方的结果是1024。  "你好"翻译成英文是"Hello"。  对话完成,共 11 条消息`

核心流程总结

  1. 初始化:建立系统提示和用户请求
  2. 循环处理:最多5轮对话处理用户请求
  3. 函数识别:AI识别需要调用的函数
  4. 函数执行:程序调用对应函数并获取结果
  5. 结果反馈:将函数结果以特定格式返回给AI
  6. 综合回答:AI基于所有函数结果生成最终回答
  7. 对话结束:当AI完成所有任务后结束对话

如何扩展更多功能?

想要添加更多功能?超级简单!

添加新闻查询功能:

复制代码
def get_news(category="technology"):
    # 实现新闻查询逻辑
    pass
​
# 添加到functions列表
functions.append({
    "name": "get_news",
    "description": "获取指定类别的最新新闻",
    "parameters": {
        "type": "object",
        "properties": {
            "category": {
                "type": "string",
                "enum": ["technology", "sports", "business"]
            }
        }
    }
})
​
# 添加到function_map
function_map["get_news"] = get_news

实际应用建议

1. 接入真实API

示例中使用模拟数据,实际应用时可以接入:

  • 天气:和风天气API、高德地图API

  • 股票:Yahoo Finance、Alpha Vantage

  • 翻译:百度翻译API、腾讯翻译API

2. 错误处理优化

复制代码
try:
    response = dashscope.Generation.call(...)
except dashscope.errors.AuthenticationError:
    print("API密钥错误")
except dashscope.errors.RequestFailure:
    print("网络请求失败")
except Exception as e:
    print(f"其他错误: {str(e)}")

3. 性能优化

  • 添加缓存机制,避免重复查询

  • 使用异步调用提高响应速度

  • 添加超时控制防止阻塞

总结

通过这个项目,我们实现了:

  1. ✅ 多功能集成:一个AI助手搞定多种需求

  2. ✅ 智能识别:AI自动判断该调用哪个函数

  3. ✅ 灵活扩展:轻松添加新功能

  4. ✅ 简洁代码:使用functions而非复杂的tools

掌握了Function Calling技术,你就能打造出真正实用的AI助手,不再是只能聊天的"人工智障",而是能帮你解决实际问题的"人工智能"!

参考资料

  1. DashScope官方文档

  2. Function Calling技术原理

作者简介:Python爱好者,专注AI应用开发。欢迎关注获取更多技术干货!
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明。

相关推荐
FreeBuf_3 小时前
微软Copilot被用于窃取OAuth令牌,AI Agent成为攻击者帮凶
人工智能·microsoft·copilot
学slam的小范3 小时前
ROS跑ORB-SLAM3遇见的问题总结
人工智能·机器人·自动驾驶
黑翼杰克斯3 小时前
如何裁剪u-boot,保留其必要功能,使体积尽可能小
linux·1024程序员节
.格子衫.3 小时前
022数据结构之树状数组——算法备赛
数据结构·算法·1024程序员节
coding消烦员3 小时前
新版 vscode 去除快捷键 Ctrl+I 显示 Copilot 的 AI 对话框
人工智能·vscode·copilot
周杰伦_Jay4 小时前
【自动驾驶开源仿真平台】Carla、AirSim、Udacity self-driving-car-sim、Apollo、Autoware。
人工智能·机器学习·自动驾驶
lpfasd1234 小时前
第十章-Tomcat性能测试与实战案例
1024程序员节
lpfasd1234 小时前
第二章-Tomcat核心架构拆解
1024程序员节