资讯详情

agent-core-java 中 InferenceAffinityModelClient 的实现解析:KV Cache 共享、释放与 vLLM 会话亲和调用

📅 2026/10/13 9:25:46 | 华诺云谱 👁 阅读
agent-core-java 中 InferenceAffinityModelClient 的实现解析:KV Cache 共享、释放与 vLLM 会话亲和调用
人工智能AI AgentAgent 框架工具调用Agent 工作流RAGMCP Clients强化学习【免费下载链接】agent-core-javaopenJiuwen agent core Java是 openJiuwen Core的 Java版本提供AI Agent开发、运行、调优与演进相关的全套SDK能力。项目地址https://gitcode.com/openJiuwen/agent-core-java点击查看免费下载本文围绕 agent-core-java 仓库中的 InferenceAffinityModelClient 展开这是一个面向 InferenceAffinity 风格vLLM推理服务的模型客户端在标准 OpenAI 兼容/v1/chat/completions调用之上额外提供cache_sharing基于session_id的会话级 KV Cache 共享与release主动释放已缓存上下文两项能力。读完本文你能掌握该客户端的配置方式、请求参数组装链路、/release_kv_cache释放协议以及它与InferenceAffinityModel、KVCacheManager之间从源码到测试的完整调用关系。客户端定位InferenceAffinity 风格的会话级缓存客户端InferenceAffinityModelClient继承自 BaseModelClient位于com.openjiuwen.core.foundation.llm.modelclients包中其源码 Javadoc 明确说明它“mirrors PythonsInferenceAffinityModelClient”参见 InferenceAffinityModelClient.java。与仓库中其他 OpenAI 兼容客户端相比它的差异化能力集中在三点会话级 KV Cache 共享在请求体中附带cache_sharing: true与cache_salt: sessionId让服务端按会话维度复用 KV Cache缓存主动释放通过私有端点POST /release_kv_cache释放指定会话、指定窗口之后的缓存能力自声明覆写supportsKvCacheRelease()返回true源码 L303-L306使上层的 KV Cache 管理组件知道可以对该客户端执行释放操作。从源码结构看它只实现了两类请求路径均写入两个类级常量L53-L54常量路径用途CHAT_COMPLETIONS_PATH/v1/chat/completions同步invoke与流式stream的补全端点RELEASE_KV_CACHE_PATH/release_kv_cache释放会话已缓存上下文的私有端点图像、语音、视频生成generateImage/generateSpeech/generateVideo在该客户端中均直接返回nullL206-L242即该 provider 面向的是纯文本对话补全场景使用时无需考虑多模态生成路径。构造方法、注册机制与两层配置两个构造入口客户端提供两个构造入口L63-L74public InferenceAffinityModelClient(ModelRequestConfig modelConfig, ModelClientConfig modelClientConfig) public InferenceAffinityModelClient(MapString, Object kwargs) // 从 kwargs 取 model_config / model_client_config主构造器先调用super(modelConfig, modelClientConfig)完成基类校验再通过createHttpClient(modelClientConfig)基于配置构建 JDKHttpClientL523-L527。第二个kwargs构造器是供ClientRegistry反射实例化使用的入口它从model_config与model_client_config两个键中取出配置对象后委托给主构造器。此外客户端在静态块中调用registerClientClass(InferenceAffinityModelClient.class)完成自注册L59-L61同时存在一个显式工厂 InferenceAffinityModelClientFactory其create(...)方法等价于直接new InferenceAffinityModelClient(modelConfig, clientConfig)见 工厂源码。provider 路由InferenceAffinity是内置 providerProviderType枚举中定义了INFERENCE_AFFINITY(InferenceAffinity, InferenceAffinity)ProviderType.java L24。在 ModelClients 的内置映射表中InferenceAffinity被直接绑定到InferenceAffinityModelClient类名L62。因此通过ModelClients.createModelClient(clientConfig, modelConfig)创建客户端时只要client_provider填写InferenceAffinity就会走内置反射路径实例化该类无需手动registerFactory。这一行为与 接入大模型 文档中列出的内置 provider 名单一致。连接层配置ModelClientConfig 关键参数构造客户端所需的连接配置来自 ModelClientConfig常用字段及其在本客户端中的实际作用如下字段默认值在本客户端中的作用clientProvider无必须为InferenceAffinity大小写兼容匹配建议按内置名称原样填写apiKey无必填。基类validateConfig()会校验api_key非空否则抛出MODEL_SERVICE_CONFIG_ERRORBaseModelClient.java L146-L160apiBase无必填。推理服务根地址客户端会自动去掉末尾/后拼接路径trimTrailingSlashL650-L659timeout60.0请求超时秒必须大于 0单次调用可通过invoke的timeout参数覆盖maxRetries3同步invoke的重试次数上限语义见下文verifySsltrue是否校验证书自签证书环境可临时关闭httpVersion无指定HttpClient版本如ModelHttpVersion.HTTP_1_1一个最小可用配置示例形态与测试用例 InferenceAffinityModelClientTest L232-L242 一致ModelRequestConfig requestConfig ModelRequestConfig.builder() .modelName(qwen2-72b) .build(); ModelClientConfig clientConfig ModelClientConfig.builder() .clientProvider(ProviderType.INFERENCE_AFFINITY) // 即 InferenceAffinity .apiKey(sk-test) .apiBase(http://localhost:8000) .verifySsl(false) .httpVersion(ModelHttpVersion.HTTP_1_1) .build(); InferenceAffinityModelClient client new InferenceAffinityModelClient(requestConfig, clientConfig);同步 invokekwargs 剥离、cache_sharing 注入与响应解析请求参数组装链路invoke(messages, tools, temperature, topP, model, maxTokens, stop, outputParser, timeout, kwargs)的执行步骤如下L115-L158kwargs 副本与内部键剥离复制kwargs后移除tracer_record_data、session_id、enable_cache_sharing三个内部键确保它们不会混入最终 HTTP 请求体——测试用例invokePostsChatCompletionAndParsesUsageToolsAndParserContent明确断言了lastPayload不包含这三个键测试 L138。参数组装buildAndSanitizeParams(...)先调用基类buildRequestParams组装标准 OpenAI 兼容参数model、messages、temperature、top_p、max_tokens、stream: false等随后执行两件事L81-L112sanitizeToolCalls(messages)清洗历史 assistant 消息中的tool_calls只保留id、type: function、index与function.name/arguments字段当enableCacheSharing true且sessionId非空时注入cache_sharing: true与cache_salt: sessionId。发送与重试makeAsyncRequest(params, timeout)按maxRetries循环发送每次失败后按2^attempt秒退避L308-L329。注意其语义与 OpenAI 客户端略有差异这里maxRetries直接作为最大尝试总次数使用for attempt maxRetries配置为 0 时一次都不发。响应解析parseResponse从choices[0].message中解析content、reasoning_content、tool_calls与usage并对 content 执行outputParser.parse(...)得到parserContentL331-L353。响应字段映射解析结果封装为AssistantMessage字段映射关系均有测试断言佐证见 测试 L139-L150响应字段映射目标说明choices[0].message.contentcontent正文内容缺失时取空串choices[0].message.reasoning_contentreasoningContent推理链内容如存在choices[0].message.tool_callstoolCalls解析为ToolCall列表非空时finishReason置为tool_calls否则为stopusage.prompt_tokens / completion_tokens / total_tokensusageMetadata输入 / 输出 / 总 tokenusage.prompt_tokens_details.cached_tokensusageMetadata.cacheTokens仅同步invoke路径会读取includeCacheTokenstrue用于观察 KV Cache 命中cacheTokens正是 cache_sharing 是否生效的直接观测点测试中prompt_tokens_details.cached_tokens: 5被断言映射到usageMetadata.getCacheTokens()测试 L143。错误处理调用链中所有异常最终收敛为StatusCode.MODEL_CALL_FAILED的BaseError错误信息分别为InferenceAffinity API async invoke error: ...同步与InferenceAffinity API async stream error: ...流式便于在日志中按 provider 定位问题。流式 streamSSE 行解析与增量 parserstream(...)与invoke的差别仅在于stream: true与 SSE 解析L160-L204。其内部流程postStream复用postJson拿到响应体后按行切分L461-L465parseStreamChunk(line)只处理data:前缀行忽略data: [DONE]结束标记对每条 chunk 解析choices[0].delta中的content、reasoning_content、tool_calls以及顶层usage与finish_reasonL414-L453。单条 chunk 解析失败JSON 异常、字段缺失不会中断流只记录 warning 并跳过若传入了outputParser则走streamWithParser累积content对累积串尝试增量解析解析成功后把结果挂到该 chunk 的parserContent并清空累积器L355-L392。测试streamParsesSseChunksAndAppliesIncrementalParser用三条 SSE 行验证了该行为测试 L154-L188data: {choices:[{delta:{content:Hello}}]} data: {choices:[{delta:{content: world},finish_reason:stop}],usage:{prompt_tokens:1,completion_tokens:2,total_tokens:3}} data: [DONE]断言点包括请求体携带model: override-model、max_tokens: 32、stream: true产出 2 个 chunk第 2 个 chunk 的finishReason为stop且usageMetadata.totalTokens为 3。releaseKV Cache 释放协议release(sessionId, messages, messagesReleasedIndex, tools, toolsReleasedIndex, model)是该客户端最具特色的方法L244-L301其协议细节请求体POST /release_kv_cache无调用侧 timeout 参数字段来源说明model入参model缺省回退modelConfig.getModelName()目标模型名cache_saltsessionId与会话绑定的缓存标识和请求时的cache_salt一致cache_sharing恒为true标记这是共享缓存的释放请求messages经convertMessagesToDictsanitizeToolCalls清洗后的消息列表服务端据此定位缓存窗口messages_released_index入参从该索引含开始的消息对应的缓存被释放tools/tools_released_index可选仅在非空时放入请求体返回语义HTTP 200 返回true并记录KV cache release successful日志非 200 记录 error 日志并返回false不抛异常其他异常包装为MODEL_CALL_FAILED错误前缀Release error: ...。测试releasePostsKvCachePayloadAndReturnsFalseForNonSuccessStatus验证了完整请求体model、cache_salt、cache_sharing、messages_released_index: 1、tools_released_index: 0以及 500 状态码时返回false的行为测试 L190-L228。与上层 KVCacheManager 的协作从源码结构看release的消费方是上下文层的 KV Cache 管理组件KVCacheManager 定义了ReleaseCapableModel接口L144-L147而 InferenceAffinityModel 实现了该接口并在内部委托给InferenceAffinityModelClient.release(...)。当上下文窗口发生不可逆变更如压缩、截断时KVCacheManager通过firstChangedDecision计算出首个变更索引ReleaseDecision若判定需要释放就对实现了ReleaseCapableModel的模型发起release(sessionId, messages, messagesReleasedIndex, tools, toolsReleasedIndex)invokeRelease 实现。对应的 API 文档可参考 KVCacheManager 与 InferenceAffinityModel。InferenceAffinityModel面向上层的统一调用入口除直接使用 client 外推荐的调用入口是 InferenceAffinityModel。它把session_id与enable_cache_sharing提升为一等参数public CompletionStageAssistantMessage invoke(Object messages, List? tools, Float temperature, Float topP, Integer maxTokens, String stop, String model, BaseOutputParser outputParser, String sessionId, boolean enableCacheSharing, MapString, Object kwargs) public IteratorAssistantMessageChunk stream(Object messages, /* 同上参数 */ ...) public CompletionStageBoolean release(String sessionId, List? messages, Integer messagesReleasedIndex, List? tools, Integer toolsReleasedIndex, String model)其内部normalizeKwargs会把sessionId/enableCacheSharing写回 kwargs 后透传给 clientL171-L179与上文 client 侧“kwargs 剥离”的逻辑正好配对。静态辅助方法buildKvCacheInvokeKwargs(session, enableKvCacheRelease)则用于从 session 对象中反射读取getSessionId/get_session_id并构造 kwargsL159-L169。需要注意的是InferenceAffinityModel创建底层 client 时走的是反射适配层ReflectiveInferenceAffinityClient按方法名 参数个数绑定invoke/stream/releaseL274-L382从源码结构看这一设计保持了 Python 版Model/ModelClient两件套的依赖解耦形态。使用边界与注意事项结合仓库文档与源码使用该客户端时有以下前提和边界服务端必须实现私有端点/release_kv_cache不属于 OpenAI 协议仅 InferenceAffinity 风格vLLM 扩展网关提供对普通 OpenAI 端点发起释放请求没有意义。cache_sharing/cache_salt字段同样依赖服务端支持。与 AscendAffinity 亲和模式互斥仓库文档 Ascend算力亲和 明确指出Ascend-affinity通过OpenAIModelClientagent_hint实现 prefetch/offload/evict与 InferenceAffinity 的 release 模式互斥二者不可同时启用。选型时可参考 examples/kv-cache-demo 中的 Ascend-affinity 调度演示。重试语义makeAsyncRequest中maxRetries是总尝试次数上限默认 3失败退避为2^attempt秒与 接入大模型 文档中 OpenAI 客户端“追加重试次数”的表述不同调参时需注意。超时覆盖invoke/stream的timeout参数秒会覆盖ModelClientConfig.timeout内部换算为Duration时不足 1ms 会向上取整到 1mstimeoutDuration。HTTP 版本HttpClient由ModelHttpClients按httpVersion构建测试用例验证了HTTP_1_1可正确生效测试 L231-L243。小结InferenceAffinityModelClient在 agent-core-java 中承担着一个明确的职责在 OpenAI 兼容对话协议之上把“会话级 KV Cache 共享”与“缓存窗口主动释放”落成两个可复现的 HTTP 行为——请求时以cache_salt绑定会话、读取cached_tokens观察命中窗口不可逆变化时经InferenceAffinityModel.release调用/release_kv_cache回收旧缓存。它的实现细节kwargs 剥离、tool_calls 清洗、SSE 增量解析、指数退避重试、200/非 200 的差异化返回均可在 InferenceAffinityModelClient.java 与 InferenceAffinityModelClientTest.java 中逐条对照验证适合作为理解该仓库“客户端—模型—KV Cache 管理”三层协作的切入点。赞分享人工智能AI AgentAgent 框架工具调用Agent 工作流RAGMCP Clients强化学习【免费下载链接】agent-core-javaopenJiuwen agent core Java是 openJiuwen Core的 Java版本提供AI Agent开发、运行、调优与演进相关的全套SDK能力。项目地址https://gitcode.com/openJiuwen/agent-core-java点击查看免费下载相关推荐ok-wuthering-waves告别手刷日常自动战斗与刷声骸一步到位实操手册ok wuthering waves告别手刷日常自动战斗与刷声骸一步到位实操手册 鸣潮日常与刷声骸还浪费多少手动时间 每晚八点开始进深黯之井、打、领、GUI 自动化计算机视觉RPA人工智能Mooncake 分布式 KV Cache 存储与共享基于 vLLM 的 KV Cache Storage Sharing 部署实战指南Mooncake 分布式 KV Cache 存储与共享基于 vLLM 的 KV Cache Storage Sharing 部署实战指南 本文是一份面向人工智能大模型模型推理服务后端Xinference Xavier 实战指南跨 vLLM 副本共享 KV Cache加速长文档查询与多轮对话推理Xinference Xavier 实战指南跨 vLLM 副本共享 KV Cache加速长文档查询与多轮对话推理 在长文档查询、多轮对话等场景中大模型推理模型推理服务人工智能大模型本地部署多模态语音上一篇TableExport终极指南3分钟实现专业级HTML表格数据导出方案下一篇Shenyu生物识别安全认证新维度创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑