Jun 15, 2025
2 min read
Rust,
LLM,
OpenAI,

大模型的函数调用在 rust 中的应用

本文深入探讨了如何在 Rust 中实现大语言模型的函数调用功能,通过实际代码示例展示了使用 DashScope API 调用通义千问模型的具体实现过程,包括完整的函数调用流程和关键代码实现。

本质上,大模型是一个文本到文本(word2word) 模型,并不存在函数调用能力. 我们一般说大模型的函数调用能力,其实指的是大模型在用户提供的问题与函数信息列表中,可以自主判断是否需要函数调用,并返回函数参数的能力.

但是就是这个能力,已经让 AI agent 应用大放异彩.有了这个能力,很多现实中不容易做到的已经变成可能,比如,一句话直接生成一个可运行的网站/游戏的那些AI编辑器. 又比如,我们可以通过大模型实现自然语言指令,转换为智能家居指令,从而达到智能控制硬件的目地.

在遵循指令方面,OpenAI 和 Claude 是这方面的佼佼者.在 deepseek v3/r1 未出现之前,国产的AI 大模型的指令能力非常的差,几乎是不可用状态,更不要说拿来做应用. 好在 deepseek v3/r1 出现之后,很多国产大模型的遵循指令能力已经大大地提高,或者或少,deepseek 功不可没.

为了演示大模型的函数调用能力,我这里以 qwen 作为例子(主要是它足够便宜,同时比较快). 如果是做生产应用,我还是推荐使用deepseek 做为首选,但是考虑到 deepseek 一直处于高负荷状态,最好有备选.

我们为什么需要函数调用?

一个很现实的例子,大模型无法知道你问的此时此刻是什么时间,什么天气,发生了什么事情. 原因是大模型的训练数据是有时效性的,哪怕现在是2025年,很多大模型的数据最新也可能最使用到了2023年.

因此,我们需要大模型”智能”地感知真实世界的信息数据.

函数调用的流程

函数调用的流程如下:

“mermaid graph TD A[用户提问] —> B{根据用户问题调用大模型} B —> C{工具信息} C{天气查询函数/当前时间函数} —> D{判断是否需要调用工具} D —是—> E[输出工具名称解析工具入参] D —否—> F[给出回复] E —> G{根据工具名称、入参调用工具} G —> H[输出工具调用结果] H —> I{根据工具结果、用户问题调用大模型} I —> J[返回大模型回复] J —> K[大模型回复] F —> K


我们要做的,就是实现上面这个流程.

## Rust 的实现

通义千问的官方 API 有两种风格,一种是 OpenAI 风格,一种是 DashScope 风格.

如果你想用 OpenAI 风格,我推荐使用这个库:

cargo add async-openai


如果使用 DashScope 风格,可以使用这个库:

cargo add async-dashscope


我这里使用 Dashscope 风格,以"现在是什么时间?" 作为例子,
我们需要实现一个获取时间的函数:

```rust
fn get_current_time() -> i64 {
	let now = Utc::now();
	now.to_string()
}

组装消息:

let mut messages = vec![MessageBuilder::default()
        .role("user")
        .content("现在是什么时间?")
        .build()
        .unwrap()];

为参数添加函数信息:

// add function call
    let request = GenerationParamBuilder::default()
        .model("qwen-turbo".to_string())
        .input(InputBuilder::default().messages(messages.clone()).build()?)
        .parameters(
            ParametersBuilder::default()
                .functions([FunctionCallBuilder::default()
                    .typ("function")
                    .function(
                        FunctionBuilder::default()
                            .name("get_current_time")
                            .description("return the current time")
                            .build()?,
                    )
                    .build()?])
                // or call .tools(value)
                .result_format("message")
                .parallel_tool_calls(true)
                .build()?,
        )
        .build()?;

带上用户消息和函数信息,我们第一次请求大模型:

let client = Client::default();
let response = client.generation().call(request).await?;

此时,大模型会自动判断是否需要调用函数工具,如果需要的话,会返回需要调用的函数名称以及参数,我们要基于此时的返回做相应的处理,我这里只做简单的处理:

    let response_message = response.output.choices.unwrap().first().unwrap().message.clone();
    // get  function call arguments
    if let Some(func_calls) = response_message.tool_calls {
        for call in &func_calls {
            if call.function.name == "get_current_time" {
                let func_response = get_current_time();
                messages.push(
                    MessageBuilder::default()
                        .role("user")
                        .content(func_response)
                        .build()?,
                );
                break;
            }
        }

拿到参数后,程序直接调用工具函数,返回数据,并附加到原来的信息中.然后,我们再次请求大模型,此时不要带上函数信息:

let request = GenerationParamBuilder::default()
            .model("qwen-turbo".to_string())
            .input(InputBuilder::default().messages(messages.clone()).build()?)
            .build()?;

        let response = client.generation().call(request).await?;

        // 返回最终总结结果
        dbg!(&response.output.text);

这样我们就得到了总结后的结果:

您提供的日期和时间是:**2025 年 6 月 5 日 16:00:00**。

现实中,不可能像上面的例子这样如此简单. 但是我们可以通过这个例子,扩展出实际可用的ai agent 应用.