OpenAI协议02、AgentForge 适配OpenAI接入核心实践

发布时间:2026/10/8 22:59:21

OpenAI协议02、AgentForge 适配OpenAI接入核心实践 前言在进入正文之前先交代一下这些文章的来龙去脉。AgentForge是一个面向 Java 开发者、从LLM 最底层能力开始构建的开源 Agent 框架。它不从高度封装的 Agent API 起步而是先建立稳定、统一、可扩展的模型抽象再逐层向上锻造 Tool、Memory、Middleware、Reasoning 与 Agent Runtime 等能力。AgentForge Agent ForgeAgent代表能理解目标、进行推理、调用工具并完成任务的智能体Forge则强调把原始智能持续加工、塑形、强化最终锻造成真正可用的产品。本系列《AgentForge 核心模块设计原理》沿着这条自底向上的路径逐个模块拆解它的设计原理与实现细节。本文聚焦AgentForge 适配 OpenAI 的接入实践统一类型与 Chat Completions 的双向映射对应模块agentforge-model-openai。开源仓库GitHubhttps://github.com/changluya/AgentForge项目文档站https://changluya.github.io/AgentForge/Gitee 镜像https://gitee.com/changluJava/agent-forge开源协议MITgitclone https://github.com/changluya/AgentForge.gitcdAgentForge mvn cleaninstall-DskipTests如果这套「自底向上」的设计对你有帮助欢迎到 GitHub 给 AgentForge 点一个 Star。一、背景与问题引入1.1、场景驱动一套 Core适配多家模型AgentForge 的 Agent Runtime 只依赖ChatModel/StreamingChatModel接口。我们希望换模型只换一个 Provider 依赖而不是改 Agent 代码。于是 OpenAI Provider 的职责被限定为协议翻译层Agent Runtime │ ChatRequest / ChatResponseProvider 无关 ▼ OpenAiChatModel / OpenAiStreamingChatModel │ Chat Completions wire ▼ OpenAI / OpenAI-compatible 服务1.2、问题引导统一类型如何落到 OpenAI wire问题AgentForge 的ChatMessage、ChatRequestParameters、ChatResponse分别怎么落到 OpenAI 的messages/ 请求字段 / 响应字段工具调用如何双向映射流式如何聚合本文逐项给出映射表与实现位置。1.3、实现边界Wire APIPOST {baseUrl}/chat/completions默认https://api.openai.com/v1release_1.x 以 Chat Completions 为第一版统一协议Responses API 采用并存 Adapter策略见第六章。1.4、Builder 参数Builder 参数默认值说明baseUrlhttps://api.openai.com/v1也支持 OpenAI-compatible 服务apiKeynull非空时发送Authorization: Bearer ...modelNamenull请求前必须有值temperaturenull非空才发送maxTokensnull映射max_tokenstopPnull映射top_pstopSequencesnull映射stopcustomParameter空透传 Provider 扩展顶层字段customHeader空追加自定义 HTTP HeaderhttpTransportJdkHttpTransportHTTP SPIconnectTimeoutMillis10000连接超时readTimeoutMillis60000读取超时重点OpenAiStreamingChatModel复用同一套配置并强制写入streamtrue与stream_options.include_usagetrue。二、核心概念2.1、统一入参ChatRequest{ListChatMessagemessages;ChatRequestParametersparameters;}ChatRequestParameters{StringmodelName();Doubletemperature();IntegermaxTokens();DoubletopP();ListStringstopSequences();MapString,ObjectcustomParameters();}2.2、统一出参ChatResponse{AiMessageaiMessage;// text toolExecutionRequestsTokenUsagetokenUsage;FinishReasonfinishReason;MapString,Objectmetadata;}重点Provider 的职责就是把 wire 字段无损地落到这两个统一对象上。三、实现思路与映射3.1、HTTP HeadersContent-Type: application/json Accept: application/json Authorization: Bearer ${apiKey} # apiKey 非空时之后追加customHeaders企业内部网关可用customHeader(...)增加租户、路由、trace 等。3.2、消息映射AgentForgeOpenAI rolecontent / 关键字段SystemMessagesystemmessage.text()UserMessage单文本usermessage.text()UserMessage多Contentusercontent[]逐条TextContent→{type:text,text:...}AiMessage纯文本assistantmessage.text()AiMessage含工具调用assistantcontent可为nulltool_calls[]ToolExecutionResultMessagetooltool_call_id message.id()content message.text()工具调用 结果回填的 wire 形态{messages:[{role:assistant,content:null,tool_calls:[{id:call_1,type:function,function:{name:getWeather,arguments:{\city\:\hangzhou\}}}]},{role:tool,tool_call_id:call_1,content:{\temperature\:22}}]}注意CustomMessage当前未实现 wire mapping遇到会抛IllegalArgumentException。3.3、参数映射AgentForge 参数Chat Completions 字段当前行为modelNamemodel必填为空本地失败temperaturetemperature非空才发送maxTokensmax_tokens非空才发送topPtop_p非空才发送stopSequencesstop非空才发送toolstools[]{type:function,function:{name,description,parameters,strict}}toolChoicetool_choiceAUTO→auto、NONE→none、REQUIRED→required、SPECIFIC→{type:function,function:{name:X}}customParameters顶层原样写入通用字段写入后覆盖同名 custom 字段构建顺序标准字段拥有最终优先级1. payload.putAll(customParameters) 2. 写入 model / messages 3. 写入 temperature / max_tokens / top_p / stop 4. 写入 tools / tool_choice重点即使customParameters写了另一个model最终仍会被modelName覆盖。3.4、响应映射OpenAI 字段AgentForge 字段choices[0].message.contentChatResponse.aiMessage().text()choices[0].message.tool_calls[]ChatResponse.aiMessage().toolExecutionRequests()usage.prompt_tokensTokenUsage.inputTokens()usage.completion_tokensTokenUsage.outputTokens()usage.total_tokensTokenUsage.totalTokens()choices[0].finish_reasonChatResponse.finishReason()id/model/createdmetadata[id] / [model] / [created]tool_calls[]映射id → ToolExecutionRequest.id、function.name → name、function.arguments → arguments保留原始 JSON 字符串不重新格式化。注意当tool_calls非空且content为空时AiMessage.text()返回null两者同时存在时两者都会保留。3.5、finish_reason 映射OpenAIAgentForgeFinishReasonstopSTOPlengthLENGTHtool_callsTOOL_EXECUTIONfunction_callTOOL_EXECUTIONcontent_filterCONTENT_FILTER其他非空OTHERnullnull3.6、响应结构异常以下情况直接抛ModelException不静默返回空choices 不存在 / 为空 / choices[0].message 不存在3.7、流式实现请求同 Endpoint强制streamtruestream_options.include_usagetrue。SSE 解析忽略空行、:注释、非data:行每个data:chunk 读取choices[0].delta.content、delta.tool_calls[]、finish_reason。delta.content→ 立即handler.onPartialResponse(...)同时本地StringBuilder聚合delta.tool_calls[]→按index分桶累加规则见协议篇 4.1不回调半成品结束 →handler.onCompleteResponse(response)。最终响应ChatResponse.builder().aiMessage(AiMessage.from(fullText,toolExecutionRequests)).finishReason(finishReason).tokenUsage(tokenUsage).metadata(metadata).build();重点最终 usage chunkchoices[]由先读 usage、再判断 choices 是否为空处理流中断时最终 usage 可能缺失ChatResponse.tokenUsage()不保证一定存在。四、实战代码4.1、非流式OpenAiChatModelmodelOpenAiChatModel.builder().baseUrl(https://api.openai.com/v1).apiKey(System.getenv(OPENAI_API_KEY)).modelName(your-model).temperature(0.2).maxTokens(1024).build();ChatRequestrequestChatRequest.builder().message(SystemMessage.from(You are a concise Java assistant.)).message(UserMessage.from(What is CAS?)).build();ChatResponseresponsemodel.chat(request);System.out.println(response.aiMessage().text());运行输出模拟终端$curl-shttps://api.openai.com/v1/chat/completions-HAuthorization: Bearer$OPENAI_API_KEY\-d{model:your-model,messages:[{role:system,content:...},{role:user,content:What is CAS?}]}{choices:[{index:0,message:{role:assistant,content:CAS means Compare-And-Swap.},finish_reason:stop}],usage:{prompt_tokens:20,completion_tokens:10,total_tokens:30}}4.2、流式OpenAiStreamingChatModelstreamingOpenAiStreamingChatModel.builder().baseUrl(https://api.openai.com/v1).apiKey(System.getenv(OPENAI_API_KEY)).modelName(your-model).build();streaming.chat(request,newStreamingChatResponseHandler(){OverridepublicvoidonPartialResponse(Stringpartial){System.out.print(partial);}OverridepublicvoidonCompleteResponse(ChatResponseresponse){System.out.println();}OverridepublicvoidonError(Throwableerror){error.printStackTrace();}});运行输出模拟终端CAS means Compare-And-Swap.4.3、OpenAI-compatible 服务OpenAiChatModelmodelOpenAiChatModel.builder().baseUrl(https://example.com/v1).apiKey(...).modelName(provider-model).build();五、兼容性、错误与边界5.1、HTTP 错误非 2xx →new ModelException(OpenAI request failed with HTTP statusCode, statusCode, responseBody)网络层 IOException →ModelException(OpenAI request failed, cause)。流式非 2xx 会累积 body 并通过handler.onError(...)返回。5.2、协议差距release_1.x 未映射developerrole、图片 / 音频多模态content、流式onPartialToolCall、refusal、logprobs、structured outputs、audio、provider reasoningAiMessage.thinking()字段位已留未接线、多choices。customParameters可临时透传请求字段但若返回结构需要框架理解仍须正式扩展 Core / Provider 类型。六、总结与演进已落地toolrole 的tool_call_id请求映射、tools/tool_choice含SPECIFIC、tool_calls非流式解析与流式按index聚合、UserMessage多Content→content[]。OpenAI 官方建议新应用优先 Responses API因此后续采用并存 AdapterOpenAiChatModel → /chat/completions、OpenAiStreamingChatModel → /chat/completions SSE未来新增OpenAiResponsesModel → /responses。上层仍只依赖 Core 接口协议迁移不侵入 Agent Runtime。参考资料[1]. OpenAI Chat Completions API官方参考[2]. OpenAI 文本生成指南[3]. 相关内部文档OpenAI 底层协议快速理解、ChatModel 核心协议层设计整理者:长路 创建时间:2026.10.5 更新时间:2026.10.5
延伸阅读

更多相关文章

2026/10/8 22:54:21

EG2131D 220V 单路半桥栅极驱动芯片|屹晶 EGmicro

一、产品整体概述EG2131D 为单通道 N‑MOS 半桥栅极驱动,SOP‑8 封装,无内置功率管,外接 N 沟 MOS/IGBT;高端 VB 悬浮耐压220V;VCC 供电11‑20V,典型 15V;图腾柱输出拉 1A、灌 1.5A;…

2026/10/8 22:54:21

计算机毕业设计选题推荐:基于大数据的全球空气污染数据可视化分析|毕业设计选题|计算机毕设|选题推荐|毕设指导|项目定制|源码|高质量项目

✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

2026/10/8 22:54:21

生物专业科研绘图不用学PS:2026年科研图片生成工具实测对比

生物专业的研究生大概都有过这种经历:实验数据明明很漂亮,却卡在一张机制示意图上——导师要求"画个信号通路图放论文里",自己对着PS教程学了三天,画出来的蛋白还是像一坨橡皮泥;想用免费素材网站&#xff0…

2026/10/9 0:14:29

JavaEE 7二手图书平台:从环境搭建到事务控制的完整实践

简介:这是一份面向高校计算机专业学生与Java初学者的完整课程设计项目资源,聚焦二手图书交易场景,基于JavaEE技术栈实现前后端分离的Web应用系统,适用于期末大作业、课程设计及JavaWeb入门实践。资源包共173个文件,含2…

2026/10/9 0:14:29

2026降AI率工具实测,哪款能压到安全线

先看一个扎心场景:论文初稿查重过了,AIGC检测却标红一片,导师甩来一句“这写得像机器,重写”。2026年高校对AIGC检测比例普遍收紧,知网、维普的AI检测报告成了毕业门槛,降AI率从可选项变成了必答题。 机械…

2026/10/9 0:14:29

C++安全编程实战:从内存管理到并发防御的完整指南

写C安全编程相关的文章,网上已经很多,但大多要么站在概念定义的角度泛泛而谈,要么直接甩一份规条清单让你背。我自己出来做事这些年,最深的体会是:很多人写C时根本没意识到自己正在踩坑,直到线上崩溃、用户…

2026/10/9 0:09:29

从自然语言到参数化CAD:text-to-cad技术路径与实操避坑指南

最近圈子里一直在聊 text-to-cad,我原本以为又是那种“演示视频很酷、落地全是坑”的概念,但自己花了大半个月把主流几条路径都跑了一遍之后,说实话,这条链路现在已经比想象中成熟得多。你给模型一句“一块 404010 的板&#xff0…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 0:04:27

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略当数万字的学位论文初稿经历开题、实验、问卷与多轮文献梳理最终成形时,绝大多数研究生都会面临一道全新的形式审查关卡:AIGC 疑似度排查。在高校毕业审核流程中,盲审前的文本检测通…

2026/10/9 0:04:27

食堂节能改造源头工厂,商用厨房设备焕新方案广受好评

商用厨房作为餐饮经营、单位供餐的核心后勤阵地,其设备配置、动线规划与运维体系直接决定后厨作业效率、运营成本与合规性。从基础的灶具、制冷存储设备,到油烟净化、水处理等配套系统,每一个环节的合理性都与食品安全、能耗管控、消防安全挂…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑