You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spring Boot实现OpenAI Assistants UI助手调用外部API的方法

基于UI创建的OpenAI助手实现Spring Boot函数调用方案

核心逻辑梳理

OpenAI助手不会直接调用你的外部API,全程通过Spring Boot中间件中转完成:

  1. 用户发送消息到你的Spring Boot服务
  2. 服务向OpenAI线程添加用户消息并触发助手运行
  3. 助手判断需要调用函数时,返回requires_action状态,附带要调用的函数名和参数
  4. 你的Spring Boot服务执行对应函数(调用外部API)并获取结果
  5. 服务把函数结果提交给助手,让助手继续运行
  6. 助手基于函数结果生成最终回复,服务获取后返回给用户

步骤1:确认UI中函数定义的正确性

  • 函数名称必须和Spring Boot中实现的函数名完全一致(大小写敏感)
  • 参数必须严格遵循JSON Schema规范,示例如下(以天气查询函数为例):
{
  "name": "get_current_weather",
  "description": "获取指定城市的当前天气信息",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "城市名称,例如北京、上海"
      }
    },
    "required": ["city"]
  }
}
  • 注意:UI里的函数不需要定义任何端点,端点是Spring Boot服务内部处理的逻辑,OpenAI只负责传递调用指令

步骤2:修改Spring Boot的运行处理逻辑

你之前的流程是创建运行后直接等待完成,现在需要加入状态判断和函数调用处理逻辑:

关键代码示例(基于OpenAI Java SDK)

import com.theokanning.openai.OpenAiService;
import com.theokanning.openai.assistants.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class AssistantFunctionService {
    private final OpenAiService openAiService;
    // 函数映射:将UI中定义的函数名绑定到具体实现
    private final Map<String, FunctionExecutor> functionMap = Map.of(
        "get_current_weather", this::invokeWeatherApi
    );

    public AssistantFunctionService(String openAiApiKey) {
        this.openAiService = new OpenAiService(openAiApiKey, 60, TimeUnit.SECONDS);
    }

    public String handleUserQuery(String threadId, String userInput) {
        // 1. 向线程添加用户消息
        openAiService.createMessage(threadId, MessageCreateRequest.builder()
                .role(Role.USER)
                .content(userInput)
                .build());

        // 2. 创建助手运行实例
        RunCreateRequest runReq = RunCreateRequest.builder()
                .assistantId("你的UI创建的助手ID")
                .build();
        Run currentRun = openAiService.createRun(threadId, runReq);

        // 3. 轮询运行状态,处理函数调用或等待完成
        while (true) {
            currentRun = openAiService.getRun(threadId, currentRun.getId());
            if (RunStatus.COMPLETED.equals(currentRun.getStatus())) {
                break;
            } else if (RunStatus.REQUIRES_ACTION.equals(currentRun.getStatus())) {
                // 处理函数调用请求
                currentRun = processFunctionCall(threadId, currentRun);
            }
            // 设置合理轮询间隔,避免API限流或无意义等待
            try {
                Thread.sleep(1200);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("运行状态轮询被中断", e);
            }
        }

        // 4. 获取助手最终回复
        List<Message> messages = openAiService.listMessages(threadId).getData();
        return messages.get(0).getContent().get(0).getText().getValue();
    }

    private Run processFunctionCall(String threadId, Run run) {
        RequiredAction action = run.getRequiredAction();
        List<ToolCall> toolCalls = action.getSubmitToolOutputs().getToolCalls();

        // 生成工具输出列表
        List<ToolOutput> toolOutputs = toolCalls.stream().map(call -> {
            String funcName = call.getFunction().getName();
            FunctionExecutor executor = functionMap.get(funcName);
            if (executor == null) {
                throw new RuntimeException("未找到对应函数实现:" + funcName);
            }
            // 解析OpenAI传递的函数参数
            Map<String, Object> params = call.getFunction().getParameters();
            // 执行函数(调用外部API)
            String apiResult = executor.execute(params);
            // 封装工具输出
            return ToolOutput.builder()
                    .toolCallId(call.getId())
                    .output(apiResult)
                    .build();
        }).toList();

        // 提交工具输出,让助手继续运行
        return openAiService.submitToolOutputs(threadId, run.getId(),
                SubmitToolOutputsRequest.builder()
                        .toolOutputs(toolOutputs)
                        .build());
    }

    // 具体函数实现:调用外部天气API
    private String invokeWeatherApi(Map<String, Object> params) {
        String city = (String) params.get("city");
        // 这里替换为实际的外部API调用逻辑,用RestTemplate或WebClient实现
        // 示例返回模拟数据
        return String.format("{\"city\":\"%s\",\"temperature\":\"26℃\",\"weather\":\"多云\"}", city);
    }

    // 函数执行器接口
    @FunctionalInterface
    private interface FunctionExecutor {
        String execute(Map<String, Object> parameters);
    }
}

步骤3:常见问题排查

  • 助手无响应/卡顿:
    • 检查是否正确处理了REQUIRES_ACTION状态,未处理的话运行会一直停滞在该状态
    • 核对函数参数定义:UI中的参数结构和代码中解析的参数必须完全匹配
    • 调整轮询间隔:间隔太短易触发API限流,太长会导致等待超时,建议1-2秒
  • 助手不触发函数调用:
    • 检查函数描述是否清晰:需要明确说明触发场景,比如“当用户询问城市天气时调用此函数”
    • 确认用户输入符合函数触发条件,比如用户说“上海今天天气怎么样”才会触发天气查询函数
  • 关于端点的误解:
    • OpenAI助手不需要访问你的Spring Boot端点,所有函数调用都是中间件中转完成的:助手只传递调用指令,中间件负责执行并返回结果,无需在UI函数定义中填写任何端点信息

内容的提问来源于stack exchange,提问作者Mikhail Saveliev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 06:50:14