尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Kimi Code agent-core-v2 的 llm 模块:一次 LLM 请求的协议无关设计与实现
AI Agent代码智能体人工智能大模型CLI【免费下载链接】kimi-codeKimi Code CLI — The Starting Point for Next-Gen Agents项目地址https://gitcode.com/gh_mirrors/ki/kimi-code点击查看免费下载llm 是 kimi-code 仓库中agent-core-v2包packages/agent-core-v2/src/human/llm/内部一个独立的 LLM 请求库它把「一次 LLM 请求」的完整能力——多协议编解码、流式事件、thinking、媒体、错误分类、重试与恢复、provider 与模型目录管理——收敛在单一模块内且不依赖任何外部 agent 框架。本文以官方模块指南 llm.md 为骨架结合源码剖析其设计原则、分层架构与请求生命周期帮助读者理解如何用「format trait requester」的组合实现多协议适配以及为何错误、重试、恢复这些横切关注点被刻意放在 llm 内核之外。模块定位llm 「一次请求」llm 是 human 层内一个独立的 LLM 请求库提供「一次 LLM 请求」的完整能力多协议请求编解码openai/openai_responses/anthropic/google-genai四种协议流式事件、thinking、媒体图片/音频/视频part错误分类、重试与恢复provider 与模型目录管理。它不依赖也不感知任何外部 agent 框架所有职责划分与扩展方式都遵循下述设计原则。九条设计原则1. 边界极简llm 只负责请求编解码与事件回传llm 不承担 auth、usage 统计、HistoryMessage/meta、compaction、switch、媒体文件系统、Tool Message 拼装——这些要么上移到 turn/agent 层要么以贡献点接入。从目录结构看llm/下只有与请求直接相关的文件message.ts、model.ts、protocol/、requester/、provider/、media/而 credentials 相关工厂位于human/credentialscredential-recovery 执行器位于llm-adapter/model/credential-recovery正是这条边界的体现。2. 流式原生、事件即契约对外只暴露一条纯可序列化的事件流定义在 requester.ts 的LlmRequestEvent联合类型中export type LlmRequestEvent | { type: llm.sent } | { type: llm.streaming.headers; headers: Recordstring, string } | { type: llm.streaming.part; part: StreamedMessagePart } | { type: llm.streaming.usage; usage: PartialTokenUsage } | { type: llm.streaming.finish; finish: FinishInfo } | { type: llm.streaming.message_id; messageId: string } | { type: llm.failed.syntax; error: LlmErrorMessagesyntax } | { type: llm.failed.remote; error: LlmRemoteErrorMessage; rawError?: unknown } | { type: llm.request.retrying } | { type: llm.done };要点另有llm.request.retrying表示调用方在 turn 之下重试本 attempt、已流出的流式状态需作废turn 层补充llm.retrying / llm.recoveringllm.sent携带最近一次 recovery 记录流式与非流式同构——非流式也走流式累积只是不发 delta事件收到即发不缓存、不兜底。3. format 屏蔽协议间差异trait 表达 provider 定制format 位于 protocol 层负责请求、响应、错误、usage 和 finish 的编解码。每种协议拥有自己的类型化 trait 接口OpenAITrait/OpenAIResponsesTrait/AnthropicTrait/GoogleGenAITrait只暴露该协议实际消费的定制点——协议不支持的 hook 在类型上无法表达而不是配了却静默无效。format 与 trait 互不 import双方只共享协议contract.ts里的中立 wire/chunk 类型。requester 是组合根——generate执行每个协议固定的流水线如prepareOpenAIRequest等交替调用纯 format 阶段lower → assemble → encode → stream parser与 trait hooksencodeCacheKey / thinking / encodeMaxCompletionTokens → convertMessage → mergeHistory → convertTool → buildParams → extractUsage定制逻辑是显式的数据流而不是捕获在 format 闭包里。以 openai/requester.ts 的prepareOpenAIRequest为例可以看到这条流水线如何显式交织 format 阶段与 trait hooks// cache key → thinking → response_format → max_completion_tokens → extraParams if (input.cacheKey ! undefined) { kwargs trait?.encodeCacheKey?.(input.cacheKey, ctx) ?? encodeOpenAICacheKey(input.cacheKey); } // ... applyThinking / responseFormatToOpenAI / encodeOpenAIMaxCompletionTokens const lowered lowerOpenAIMessages(input, { ... }); // format: lower const converted lowered.flatMap(({ source, message }) // trait: convertMessage trait?.convertMessage undefined ? [message] : ... ); const merged trait?.mergeHistory?.(history, ctx) ?? history; // trait: mergeHistory const tools input.tools.map(tool trait?.convertTool?.(tool, ctx) ?? defaultOpenAITool(tool)); // trait: convertTool const params assembleOpenAIRequest(input, { messages: merged, tools, kwargs }); // format: assemble const finalParams trait?.buildParams?.(params, ctx) ?? params; // trait: buildParams return encodeOpenAIRequest(finalParams); // format: encode职责划分上endpoint/环境变量解析与默认 headers 属于 providerconnection错误归类是 requester 选项模型能力是 provider binding 字段——都不是 format 的职责。每个 base 的公开接缝是 contract trait requesterformat、lower、patterns 是 requester 流水线的内部模块——只有 bases 内代码和测试可以 importlint 强制。协议差异不允许泄漏到 turn 或 requester 的装饰层。4. 错误两层模型内部 throw SDK 原生错误本地请求校验抛共享的SyntaxRequestFormatErrorsyntax-errors.ts由 requester 经toLlmSyntaxErrorMessage统一转换不加中间层。对外只有两类错误llm.failed.syntax本地消息语法错误不重试llm.failed.remote远程流式错误细分为 connection / timeout / rate_limit / quota_exhausted / context_overflow / request_structure 等由 format 在边界完成转换。错误 kind 的完整定义在 errors.ts包含syntax/abort/connection/timeout/status/rate_limit/quota_exhausted/overloaded/context_overflow/request_too_large/request_structure/image_format/empty_response/provider/unknown。其中远程错误还携带statusCode、requestId、retryAfterMs、headers等结构化信息LlmStatusErrorInfo为 retry 尊重 Retry-After 提供数据基础。5. 无状态内核 turn 驱动的编排generate(config, content, control)是无状态函数错误走 onEvent 不 throw。turn machine 直接 invoke 请求 actorcreateRequestActoractor 包装单次请求messageResolvers、abort 作用域、事件 sendBackturn 借助 retry.ts / recovery.ts 的纯策略函数驱动重试与恢复recovery是一条由调用方组装的策略链engine 先尝试credentialsRecovery再尝试配置的媒体降级等替换消息策略。每个策略的纯函数propose返回自描述记录{strategy, action}、可选替换attemptMessageOverride、可选不透明beforeNextAttempt副作用。turn 执行beforeNextAttempt和/或替换消息并重进thinkingattempt 重置为 1覆盖值沿用到同一步的后续重试直到被替换或在进入下一步前清空retry走retrying状态的 backoff尊重 Retry-After两者分别由 turn 对外补发llm.recovering / llm.retrying事件empty response由 turn 在llm.done时经纯函数emptyResponseError判定并重新转为llm.failed.remote进入同一失败级联abort由 turn 持有的 AbortController 承载controller 经LlmInput.signal传入 request actorturn 在turn.abort时直接 abort 它请求随即以llm.failed.remote收尾request actor 不自建 controller、回收时不触碰任何 signal正常完成的请求绝不可能误 abort 共享 signal。累积器accumulator由 turn 持有并随事件流喂入在llm.retrying / llm.recovering / llm.request.retrying时 rollback 并重建每次 attempt 从零累积从而尽可能保留中断现场turn 在llm.done时从累加器 finish 出完整消息。被中断 attempt 已实时转发给父机/UI 的 part 不回收只重置累加器与 tool call id normalizer。retry 的默认参数在 retry.tsDEFAULT_MAX_RETRY_ATTEMPTS 10指数退避BASE_DELAY_MS 500、RETRY_FACTOR 2、上限MAX_DELAY_MS 32_000并加 25% 抖动可重试的 status code 为[408, 409, 429, 500, 502, 503, 504, 529]quota_exhausted/context_overflow/request_structure等明确不重试除非infiniteRetry。6. 不兜底配置是什么就是什么beta 特性、thinking、empty response 等场景先定义明确报错条件在请求阶段报错并引导用户修正而不是静默兜底。例如 Anthropic 协议被拆分为anthropic/anthropic_beta不传就不发传错就报错需要 beta 特性的 provider 必须显式使用anthropic_beta协议。7. 一切可变能力都是贡献点provider、媒体上传/降级、usage、traceId、错误恢复compaction/媒体降级都通过扩展点接入llm 内核不含这些概念。LlmRequestConfig.credentialProvider就是凭证贡献点resolve / canRecover / invalidate由调用方在每次 attempt 前解析请求因此始终携带新鲜凭证。8. 数据即数据model 是无函数的纯数据——endpoint url model 唯一标识一个模型——可序列化、可直接作为 generate 输入。见 model.tsexport interface LlmModel extends LlmConnection { readonly provider: string; readonly model: string; readonly capability: ModelCapability; readonly maxContextSize?: number; readonly maxInputSize?: number; } export function modelKey(model: LlmModel): string { return model.baseUrl undefined ? model.model : ${model.baseUrl}#${model.model}; }catalog 是provider - models的派生缓存依赖方向只能从 models-dev 指向 llm 内部不能反向依赖。9. Message 转换用编译器范式通用Message[]到协议报文是 N:M 转换用 MLIR 式 Pattern Rewriter有序、独立的 Pattern 将 MessageRange 替换为 MessageRange最后 loweringtoolMessageConversion、media 映射也是 Pattern。实现位于 protocol/patterns.ts 与 protocol/rewrite.ts。OpenAI base 中toolMessageConversion为extract_text时走toolResultToPlainText、keep_parts时不应用 media pattern、默认extractToolMedia见 openai/format.ts。分层架构llm/ ├── message.ts 通用 Message 模型按 role 拆分tool 声明独立 ├── model.ts LlmModel纯数据providermodelendpoint 覆盖 ├── capability.ts / thinking.ts / usage.ts / finish-reason.ts / response-format.ts / syntax-errors.ts ├── errors.ts LlmErrorKind 两层syntax | remote 各细分 kind ├── toolCallIdNormalizer.ts 流式 tool call id 去重重复的 raw id 按序重映射为新 id │ ├── protocol/ 协议通用层跨基座共享 │ ├── base.ts ProtocolName / ProtocolBaseTTrait / ProtocolRequesterOptions / TraitContext │ ├── format.ts ProtocolFormatcreateStreamParser(sink 回调 resolveUsage 选项) │ ├── connection.ts ProviderConnectionendpoint 环境变量声明 默认 headers │ ├── thinking.ts ThinkingStrategy → ThinkingContribution → applyThinking → AppliedThinking │ └── patterns.ts / rewrite.ts MLIR 式 Pattern RewriterMessage N:M 转换 │ ├── requester/ │ ├── requester.ts LlmRequester.generate(config, content, control) │ │ ExtraParams 按协议带类型 {openai?, responses?, anthropic?, googleGenai?} │ │ LlmRequestConfig.credentialProvider凭证贡献点 │ │ resolve/canRecover/invalidate由调用方在每次 attempt 前解析 │ │ 工厂与 credentialsRecovery 策略位于 human/credentials │ │ createStaticCredentialProvider / createOAuthCredentialProvidercreateKimiOAuthCredentialProvider │ │ 适配 Kimi OAuth token供 direct 调用方使用的 │ │ runWithCredentialRecovery / streamWithCredentialRecovery 执行器 │ │ 位于 llm-adapter/model/credential-recovery │ ├── actor.ts 请求 actor包装单次请求的 fromCallback │ │ messageResolvers、abort 作用域、事件 sendBack由 turn invoke │ ├── retry.ts / recovery.ts 重试/恢复策略纯函数由 turn machine 驱动propose 为纯函数 │ ├── empty-response.ts emptyResponseError空响应判定纯函数由 turn 在 llm.done 时转为 llm.failed.remote │ └── bases/ 四个协议基座openai / openai-responses / anthropic / google-genai │ 各自含 contract / format / lower / patterns / capability / extra-params / trait / requester │ 公开接缝contract / trait / requesterformat / lower / patterns 保持内部 │ ├── provider/ │ ├── definition.ts ProviderDefinition{id, protocols{basetraitconnectionclassifyErrorcapability}, media, models} │ │ createProvider()无 registry→ Provider{listModels, resolveModel, createRequester} │ └── providers/ standard 等内建 provider经贡献点注册 │ ├── provider-catalog.ts xstate 状态机refresh/upsert/remove/ping 输入changed 输出 │ provider - models 结构远程 pulled 与本地 models 双真相源 │ └── media/ 媒体贡献点cache / degrade / ref / resolver / store / upload通用 Message 模型与流式 partmessage.ts 定义按 role 拆分的消息模型SystemMessage/UserMessage/AssistantMessage/ToolMessagetool 声明ToolDescription独立于消息。内容 part 有text/think/image_url/audio_url/video_url五种ContentPart流式 partStreamedMessagePart额外包含ToolCalltype: function与ToolCallPart流式参数增量。mergeInPlace负责把文本/think/工具参数增量合并进既有 partcreateMessageAccumulator实现流式累积按_streamIndex映射 tool call 序号、合并参数碎片、延迟 flush 空 think 块最终finish()产出完整AssistantMessage。协议基座bases四个基座——openai、openai-responses、anthropic、google-genai——各自含 contract / format / lower / patterns / capability / extra-params / trait / requester。每个 base 导出ProtocolBase如openAIBase: ProtocolBaseOpenAITrait包含capability与createRequester见 protocol/base.ts。OpenAI base 的执行openai/requester.tsexecuteOpenAIRequest用官方 SDK 的chat.completions.create(params, {signal}).withResponse()发起流式请求先发llm.sent、随后llm.streaming.headers每个 chunk 交给format.createStreamParser(...)解析通过 sink 回调输出streaming.part / streaming.finish / streaming.message_id / streaming.usage出错时由convertOpenAIErroropenai/format.ts分类为 timeout / connection / quota_exhausted / rate_limit / status 等远程错误。请求参数中max_completion_tokens有 128K 上限CHAT_COMPLETIONS_MAX_OUTPUT_TOKENS_CEILING并按模型前缀o1.../gpt-5自动选择max_completion_tokens还是max_tokens。provider 定义与连接解析provider/definition.ts 中ProviderDefinition声明{id, protocols, media?, models?}createProvider()无 registry 地构造Provider提供listModels / resolveModel / createRequester。ProviderConnection.endpoint()protocol/connection.ts声明apiKeyEnv / baseUrlEnv / defaultBaseUrlresolveModelConnection在每次请求前按「model 显式值 → 环境变量 → 默认值」的优先级补全 baseUrl 与 apiKey——这保证了凭证/endpoint 解析发生在 requester 边界且每次 attempt 都重新解析。provider-catalog模型目录状态机provider-catalog.ts 是 xstate 状态机输入refresh / upsert / remove / ping输出changed维护provider - models结构远程 pulled 与本地 models 双真相源。请求生命周期端到端generate(config, content, control)收到请求调用方在每次 attempt 前把config.credentialProvider解析成带完整凭证的 modelmachine 路径由 request actor 完成请求因此始终携带新鲜凭证凭证刷新恢复可恢复的 401 →credentials.invalidate()以llm.recoveringstrategy 为credentials发出在重发时自然重新解析。不经状态机的 direct 调用方——ping、generate、full compaction、媒体上传——通过runWithCredentialRecovery/streamWithCredentialRecovery共享同一套单次重试恢复requester 的prepare*Request函数将纯 format 阶段与 trait hooks 组合为协议 requestParamsformat 将通用Message[]经 Pattern Rewriter 降低trait 在其间调整 kwargs、转换消息、合并历史、转换 tools 并收尾 paramsexecute*Request调用官方 SDK流式 chunk 经无状态 parser 回调转换为llm.streaming.part / streaming.usage / streaming.finish / streaming.message_id事件错误由 format 转换为llm.failed.*成功时 requester 发出llm.done失败时以llm.failed.syntax / llm.failed.remote收尾、不再发llm.done。turn 层在此基础上补齐编排语义turn 在llm.done时经emptyResponseError判定空响应并重新转为llm.failed.remoteturn machine 对llm.failed.remote先尝试恢复由 engine 组装的策略链——可恢复 401 的凭证刷新在前、替换消息策略在后——经纯函数propose产出带不透明beforeNextAttempt副作用的记录发llm.recovering再按策略 backoff 重试尊重 Retry-After发llm.retrying耗尽后才将 turn 置为失败turn 持有 HistoryAccumulator 随事件流累积在llm.retrying / llm.recovering / llm.request.retrying时 rollback 并重建累加器llm.done时 finish 出完整消息usage 统计、trace、compaction、媒体降级均以插件/贡献点身份挂接在事件流上。已被否决的方案不要再引入该文档同时记录了一批已被否决的设计供后续维护者避坑拆分llmActor/llmStreamActor两个 actor——每次请求一个 actor非流式也走流式累积给请求 actor 再包一层专用 llm 状态机——turn machine 直接 invoke actor 并持有重试/recovery额外的 machine 层没有任何被消费的状态DDD 领域方法包装Generation Domain 等——用 format/trait/provider 分层用一个跨协议 trait 大包承载所有厂商 hooks旧的ProtocolTrait——按协议拆分的类型化 trait由 requester 的请求流水线组合把 trait 绑定进 formatcreateOpenAIFormat(trait)闭包或把 trait hooks 作为 formatRequest 选项传入——requester 流水线显式交替调用 format 阶段与 trait hooks双方只共享中立的contract.ts类型函数式toWireMessage/WireAdapter命名——用 adapter interface命名中不出现 WireProvider registry /defineProvider——用createProvider导出 const出站时把 system 消息 hoisting 出原位——system 消息留在历史原位转换llm 输出{message, meta}的 Context 对象——meta 归 turn 领域llm 只发事件在 llm 与 turn 各实现一次 accumulator——accumulator 只由 turn 持有随事件流喂入beta 特性无限兜底——协议拆分为anthropic/anthropic_beta不传就不发传错就报错需要 beta 特性的 provider 必须显式使用anthropic_beta协议。结语llm 模块的设计精髓在于「边界」与「组合」边界上只保留「一次请求」的编解码与事件回传横切关注点全部外置为贡献点组合上以 requester 为组合根用显式流水线交替驱动纯 format 阶段与类型化 trait hooks让多协议差异既可在类型层面表达、又不会泄漏到上层。配合 turn 驱动的重试/恢复、两层错误模型与「数据即数据」的纯模型设计这套架构为 Kimi Code 的 agent 运行时提供了稳定、可扩展、可测试的 LLM 请求底座。深入阅读可继续查看 模块指南、requester 契约 与四个协议基座目录以及packages/agent-core-v2/test下的对应测试用例。赞分享AI Agent代码智能体人工智能大模型CLI【免费下载链接】kimi-codeKimi Code CLI — The Starting Point for Next-Gen Agents项目地址https://gitcode.com/gh_mirrors/ki/kimi-code点击查看免费下载相关推荐Yao gRPC 网关设计与实现解析一套令牌、两种协议统一进程、Shell、MCP、LLM 与 Agent 调用面Yao gRPC 网关设计与实现解析一套令牌、两种协议统一进程、Shell、MCP、LLM 与 Agent 调用面 本文以仓库中的 grpc/DESIGN.Agent 框架后端低代码RAGBabelDOC PDF翻译实战指南5 分钟出双语版扫描件、离线场景全覆盖BabelDOC PDF翻译实战指南5 分钟出双语版扫描件、离线场景全覆盖 拿到一份几百页的英文论文 PDF想保留版式翻译往往卡在三处在线工具把版式拆人工智能AI 应用NLP计算机视觉5个步骤实现数据管道CI/CDmodern-data-warehouse-dataops自动化部署指南5个步骤实现数据管道CI/CDmodern data warehouse dataops自动化部署指南 现代数据仓库的自动化部署是提升开发效率和保证数据质量的上一篇css.gg API速率限制与缓存策略详解下一篇告别Eject最完整react-app-rewired实战指南从安装到高级配置创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

Isaac Sim关节驱动配置避坑指南:从物理原理到真机迁移

Isaac Sim关节驱动配置避坑指南:从物理原理到真机迁移

1. 为什么“5分钟搞定”在Isaac Sim里是个危险的幻觉刚接触Isaac Sim的新手,看到标题里“5分钟搞定关节驱动配置”,第一反应往往是——太好了,终于不用啃那本厚得能当板砖的官方文档了。我当年也是这么想的,结果在JointDrive节点上…

📅 2026/9/28 9:21:16
Spring Boot多模块依赖管理:父工程与子工程区别及最佳实践

Spring Boot多模块依赖管理:父工程与子工程区别及最佳实践

Spring Boot 多模块项目依赖管理:父工程与子工程的区别与最佳实践先聊一个我在实际项目里经常遇到的场景。你接手一个维护了一两年的系统,代码全塞在一个Maven工程里,里面Service层几千行,各种工具类堆在同一个包下面,…

📅 2026/9/28 9:21:16
基于Python的深度学习新闻推荐系统:从源码到毕设落地实战

基于Python的深度学习新闻推荐系统:从源码到毕设落地实战

简介:这份资源是面向计算机相关专业学生与开发者的毕业设计级新闻推荐系统源码,采用Python结合深度学习技术实现,可用于毕业设计、期末课程设计或大作业参考。项目评审分达95分以上,经过严格调试,确保可运行&#xff0…

📅 2026/9/28 9:21:16
MORE NEWS

更多资讯

📰

从CANoe到TSMaster:车载总线测试工具链迁移实战指南

搞车载总线测试的工程师,电脑里大概率都装着一套CANoe。我最早接触CANoe是刚入行那会儿,跟着前辈在项目里做网络测试,从报文发送、DBC解析到UDS诊断,基本全是靠Vector这套工具撑起来的。说实话,CANoe确实是这个行业的标…

📰

从刷榜到用榜:GitHub Trending 的增量逻辑、项目筛选与高效落地

1. 日榜的"热度"到底是怎么算出来的先别急着收藏仓库。每天打开 GitHub 的 Trending 页面,你看到的是过去 24 小时内 Star 增量最高的仓库,周榜和月榜则分别看一周、一个月内的增量。官方没有公开完整排序算法,但用久了会发现&…

📰

【Java开发MCP】SSE模式开发并集成MCP:TaoToken统一Key接入与SpringAI WebFlux配置骨架

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

📰

OpenCompass 高效评测:Partitioner 任务切分与 Runner 执行后端实战指南

模型评测人工智能大模型AI 评测 【免费下载链接】opencompass OpenCompass is an LLM evaluation platform, supporting a wide range of models from OpenAI, Anthropic, Gemini, Qwen, GLM, DeepSeek, etc, across 100 datasets covering knowledge, reasoning, coding, scie…

📰

快速搭建网站的工具怎么选?3个方案省下5万冤枉钱

快速搭建网站的工具怎么选?3个方案省下5万冤枉钱 网站做好了没人访问,这是很多老板最头疼的事。你花大价钱做的官网,设计精美、功能齐全,但打开一看,流量为零,咨询为零。这时候你才意识到,问题不在“做没做”,而在“怎么快速做出来并推向市场”。面…

📰

中文文本分类落地:BERT+CNN+RNN+GCN的生产级链路重构

简介:本资源是一套面向高校计算机与人工智能方向学生的高分课程设计实现方案,聚焦中文文本分类任务,融合CNN、RNN、GCN与BERT四大主流模型,提供端到端可运行的Python工程代码,适用于自然语言处理课程设计、期末大作业及…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬