为模型赋能:解析 Bella OpenAPI 的 Function Call 机制
引言:为什么需要 Function Call 能力
大型语言模型(LLM)的应用已从简单对话迈向复杂工具调用场景,Function Call 能力成为构建实用 AI 应用的关键。然而,市场上的模型在这一能力上存在显著差异:OpenAI、Claude、Qwen-max 等商业模型原生支持 Function Call,而包括 DeepSeek R1 在内的许多开源模型则不具备这一能力。这种能力鸿沟给企业构建统一 AI 平台带来了挑战。通过深入分析 Bella OpenAPI 的代码实现,我们揭示其如何通过创新的模拟机制,为不支持 Function Call 的模型扩展了这一关键能力。
DeepSeek R1 的局限与行业现状
DeepSeek R1 作为一款强大的开源大语言模型,在文本生成、知识理解等方面表现出色,但它与众多开源模型一样,面临一个共同的局限:不支持原生的 Function Call 能力。这一局限使得它在工具调用、结构化输出等企业级应用场景中难以直接应用。
当前行业现状是:
- 大部分商业模型支持完善的 Function Call
- 部分开源模型提供有限支持
- DeepSeek R1 等许多模型完全不支持此功能
这种不平衡状态迫使使用者要么锁定在高成本的商业模型上,要么放弃 Function Call 带来的强大能力。
代码解析:Bella OpenAPI 的模拟机制
通过分析 Bella OpenAPI 的源代码,我们可以看到其创新的 Function Call 模拟实现方式。核心机制位于 ToolCallSimulator 类和 SimulationHepler 类中:
// ToolCallSimulator.java
@Override
public CompletionResponse completion(CompletionRequest request,
String url, T property) {
if(property.isFunctionCallSimulate()) {
CompletionRequest req =
SimulationHepler.rewrite(request);
if(req != null) {
processData.setFunctionCallSimulate(true);
CompletionResponse resp = delegator.completion(req,
url, property);
try {
// 解析为 function call,替换第一个 choice
Choice choice =
SimulationHepler.parse(resp.reasoning(), resp.content());
choice.setFinish_reason(resp.finishReason());
resp.getChoices().set(0, choice);
} catch (Exception e) {
LOGGER.info(resp.content(), e);
}
return resp;
}
}
return delegator.completion(request, url, property);
}
这段代码展示了 Bella OpenAPI 的适配器模式,通过 functionCallSimulate 开关控制是否启用模拟功能。当启用时,系统会:
- 重写原始请求(SimulationHepler.rewrite(request))
- 发送重写后的请求给 LLM
- 解析模型返回内容,转换为标准的 Function Call 格式
Prompt Engineering 的奥秘
模拟机制的核心在于 function_call_template.pebble 模板文件,这是一段精 心设计的提示工程:
<目标>
本 prompt 的目标是为模型引入函数调用能力,但在此过程中,必须保留模型默认的回
答行为,提供详尽、全面、自然的内容,除非用户明确要求简洁回答。
</目标>
用户在跟一个 agent 进行互动,现在需要你基于`agent 基础信息`及其与用户的`互动
过程`,按照`决策要求`分析,下一步该从`候选动作集`中采取什么动作, 按照`输出格
式要求`输出结果。
...
## 候选动作集
```python
{% for func in functions %}
{{ func }}
{% endfor %}
def directly_response(type: str, content: str):
"""直接回复用户,提供完整、详尽、自然的答案,或收集必要参数信息。
...
"""
pass
这个模板通过几个关键策略实现了 Function Call 模拟:
- 结构化指令:明确告诉模型(包括 DeepSeek R1)如何输出 Python 函数调用格式
- 角色扮演:让模型扮演具有工具使用能力的 Agent
- 动态注入函数定义:将原始请求中的函数定义动态转换为模型可理解的 Python 定义
- 统一响应格式:通过严格的输出格式要求确保一致性
解析引擎:从文本到结构化调用
当 DeepSeek R1 等模型生成文本响应后,PythonFuncCallParser
和PythonFuncCallListener
类负责将文本解析为结构化的 Function Call:
public static CompletionResponse.Choice parse(String reasoning,
String content) throws IOException {
PythonFuncCallListener sfc = new
PythonFuncCallListener(null);
PythonFuncCallParser parser = new PythonFuncCallParser(new
StringReader(content), sfc);
parser.parse();
return sfc.getToolcalls().isEmpty()
? CompletionResponse.assistantMessageChoice(reasoning,
sfc.getBuffer().toString())
: CompletionResponse.toolcallChoice(reasoning,
sfc.getToolcalls());
}
这种解析能力使 Bella OpenAPI 能够从 DeepSeek R1 生成的文本中提取函数调用信息,并转换为标准格式,从而实现与原生支持 Function Call 的模型相同的行为。
实际效果:DeepSeek R1 的能力扩展
通过 Bella OpenAPI 的 Function Call 模拟机制,DeepSeek R1 获得了以下能力扩展: