LLM 层:Prompt 模型、Executor、多 Client 与会话
30 秒导读: 上一章 讲的节点(比如
nodeLLMRequest)最终都要"跟大模型说句话"。这一层就是那句话怎么被表示、怎么被送出去、怎么在多个模型/厂商之间切换。核心是三层分工:Prompt/Message(不可变的对话数据)→ PromptExecutor(决定用哪个模型、怎么路由)→ LLMClient(把统一数据编码成各家 HTTP API)。Agent 侧再包一层 会话(session),让节点安全地读写这段历史。
1. 这是什么(零基础也能懂)
一句话定义: 这一层把"和 LLM 对话"拆成"数据(说了什么)、"调度(找哪个模型)、"翻译(怎么发给 OpenAI/Anthropic)"三件互不耦合的事。
解决什么问题: 你写 agent 时不想被绑死在某一家。今天用 GPT-5、明天想换 Claude、或想让同一段对话历史在两家之间来回切——只要对话数据本身跟厂商无关,切换就只是"换个翻译官"。Koog 的做法正是:对话历史用一套中立的数据结构存,每家厂商各有一个 client 负责编解码。
核心组件一览:
| 组件 | 白话职责 | 所在模块 |
|---|---|---|
Prompt / Message | 一段不可变的对话历史(系统/用户/助手消息 + 参数) | prompt-model |
PromptBuilder | 用 DSL 拼出 Prompt 的构造器 | prompt-model |
LLMParams | 温度、maxTokens、结构化 schema、tool choice 等调用参数 | prompt-model |
PromptExecutor | "把 prompt 送出去"的统一入口;可组合出多模型/路由/轮询 | prompt-executor-model |
LLMClient | 单个厂商的真实 HTTP 客户端(编码请求、解码响应) | prompt-executor-clients/* |
AIAgentLLMContext + session | agent 侧的会话入口,节点通过它读写历史、发起请求 | agents-core |
一句话直觉: 把 Prompt 想成一封跟快递公司无关的信;PromptExecutor 是前台(决定这封信交给哪家快递);LLMClient 是具体那家快递(把信塞进它家规定的信封格式)。换快递不用重写信。
2. 顶层全景(它大概怎么转)
一次"节点请求 LLM"从上到下穿过这四层。怎么读这张图:从上到下是一次请求的下沉路径,箭头是调用方向;虚线是"同一份 Prompt 被重新编码"的关键点。
节点(02 章) agent.nodeLLMRequest 之类
│ llm.writeSession { requestLLM() }
▼
┌─────────────────────────────┐
│ AIAgentLLMContext │ 持有 prompt / model / tools / executor
│ · writeSession(写锁) │ 发请求 + 把回复 append 回 prompt
│ · readSession(读锁) │
└─────────────┬───────────────┘
│ executor.execute(prompt, model, tools)
▼
┌─────────────────────────────┐
│ PromptExecutor(可组合) │ MultiLLM / Routing / RoundRobin
│ 1. resolveModel → 选出有效模型 │
│ 2. clientFor(provider) → 选 client │
└─────────────┬───────────────┘
│ client.execute(prompt, model, tools)
▼
┌─────────────────────────────┐
│ LLMClient(单厂商) │ OpenAI / Anthropic / Google / ...
│ · 把中立 Prompt 编码成本家 API 请求 ┄┄┄> 换 model 就换 client,重新编码同一份历史
│ · HTTP 调用,解码回 Message.Assistant │
└─────────────┬───────────────┘
│ Message.Assistant(回复)
▼
回到 writeSession,appendPrompt { message(response) }
主线走一遍(高层):
- 节点在
writeSession里调requestLLM()。 - 会话把当前
prompt+tools交给PromptExecutor.execute(...)。 - Executor 先
resolveModel决定真正用哪个模型(可能触发 fallback),再按 provider 挑出一个LLMClient。 - Client 把这份中立的 Prompt 编码成本家 HTTP 请求,发出,解码回
Message.Assistant。 - 会话把这条助手消息 append 回 prompt,历史增长一轮。
关键卖点就在第 3-4 步:prompt 从头到尾没变过,换模型/换厂商只是换了个 client 重新编码同一份历史——这就是"LLM 可随时切换、历史无缝适配"。
3. 核心原理(逐个机制,由浅入深)
3.1 Prompt 与 Message:不可变的对话历史
要解决的小问题: 对话历史要能被反复拷贝、裁剪、换参数,还不能被并发改乱。
思路: 用 Kotlin 的 data class + 密封类型(sealed),把历史做成不可变值——任何"修改"都返回新对象,老对象不动。
Prompt 就是三元组:一串消息 + id + 参数。
// 示意,非源码:Prompt 的形状
data class Prompt(
val messages: List<Message>, // 不可变的对话历史
val id: String,
val params: LLMParams = LLMParams()
)
真实定义在 prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/Prompt.kt:25(Prompt)。所有"改"都是拷贝:withMessages(Prompt.kt:129)、withParams(Prompt.kt:138)、withUpdatedParams(Prompt.kt:223)都返回新的 Prompt。它还顺手算两个只读量:latestTokenUsage(取最后一条助手消息的 token 数,Prompt.kt:102)和 totalTimeSpent(首尾消息时间差,Prompt.kt:117)。
Message 是一棵密封树,按角色分三种,每种由若干 MessagePart 组成:
| 消息类型 | Role | 允许的 part | 典型来源 |
|---|---|---|---|
Message.System | System | 只允许 Text | 系统提示/人设 |
Message.User | User | RequestPart(Text、Attachment、Tool.Result) | 用户输入、工具结果回填 |
Message.Assistant | Assistant | ResponsePart(Text、Reasoning、Tool.Call) | 模型回复 |
真实定义在 prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/message/Message.kt:21(Message sealed interface)。MessagePart 用方向来分类(Message.kt:246):RequestPart 是发给模型的、ResponsePart 是模型返回的、ContentPart(Text/Attachment)两个方向都行。工具相关的两种 part 尤其重要:MessagePart.Tool.Call(模型要调工具,Message.kt:348)和 MessagePart.Tool.Result(工具结果,Message.kt:387)— —它们让"一次工具往返"也能被存进同一条历史里(工具系统细节见 04 章)。
每条消息还带 metaInfo:请求侧是 RequestMetaInfo(只有时间戳,Message.kt:441),响应侧是 ResponseMetaInfo(带 totalTokensCount/inputTokensCount/outputTokensCount/modelId,Message.kt:489)——token 统计和跨模型溯源都靠它。
3.2 PromptBuilder DSL:把历史拼出来
要解决的小问题: 手写一串 Message.System(...)、Message.User(...) 太啰嗦。
思路: 给一个 prompt("id") { ... } 的类型安全 DSL,块里按顺序 system/user/assistant 即可。
// 示意,非源码:最小用法
val p = prompt("example") {
system("You are a helpful assistant.")
user("法国的首都是哪?")
}
入口函数 prompt(id, params, clock, build) 在 prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/dsl/PromptDSL.kt:35,内部委托给 Prompt.build。构造器本体 PromptBuilder 在 prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/dsl/PromptBuilder.kt:36:system(:68)、user(:117/:131)、assistant(:192)、toolCall(:270)、toolResult(:170)、reasoning(:245)逐个往内部 可变列表加消息,最后 build()(PromptBuilder.kt:359)冻结成不可变 Prompt。
要在旧历史上追加? 用 prompt(existing) { ... }(PromptDSL.kt:74),底层是 PromptBuilder.from(prompt)(PromptBuilder.kt:44)先把老消息拷进来再续写——这正是会话里 appendPrompt 的基础(见 3.6)。
3.3 LLMParams:一次调用的旋钮
要解决的小问题: 温度、最大 token、要不要强制调工具、要不要结构化输出——这些"怎么生成"的参数得跟"说了什么"分开存。
LLMParams 就是这组旋钮,定义在 prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/params/LLMParams.kt:30。
| 字段 | 作用 |
|---|---|
temperature | 随机性;构造时校验必须在 0.0..2.0(LLMParams.kt:41) |
maxTokens | 输出上限 |
numberOfChoices | 要几个候选回复 |
speculation | 推测式生成(如 OpenAI PredictedOutput) |
schema | 结构化输出的 JSON schema(见 3.7) |
toolChoice | 工具调用行为:Auto / None / Required / Named(name) |
user | 追踪用的用户标识 |
additionalProperties | 逃生口:塞任意自定义参数 |
两 个设计点值得记:
default(other)合并(LLMParams.kt:68):当前实例里为null的字段用other的值补上——用于"局部覆盖 + 全局默认"。ToolChoice是密封类(LLMParams.kt:270):Auto/None/Required/Named四态,会话里的setToolChoiceRequired()等便捷方法就是改这个(见 3.6)。
3.4 PromptExecutor:统一入口 + 可组合的调度
要解决的小问题: "把 prompt 送出去"这件事,要能在"单模型直连""多厂商共存""同厂商多 key 轮询"之间自由组合,还不改调用方代码。
思路: 定义一个统一抽象接口,所有变体都实现它;调用方永远只依赖接口。
接口 PromptExecutorAPI 在 prompt/prompt-executor/prompt-executor-model/src/commonMain/kotlin/ai/koog/prompt/executor/model/PromptExecutorAPI.kt:18,核心方法:
| 方法 | 干什么 |
|---|---|
execute(prompt, model, tools) | 发一次请求,拿一条 Message.Assistant(:29) |
executeStreaming(...) | 流式,返回 Flow<StreamFrame>(:44) |
executeMultipleChoices(...) | 多候选(默认降级为单条,:60) |
moderate(prompt, model) | 内容审核,返回 ModerationResult(:80) |
resolveModel(model, op) | 把"想要的模型"解析成"实际用的模型"(:94) |
models() | 列出所有可用模型(:165) |
PromptExecutor 本身是个 expect abstract class(多平台声明,prompt-executor-model/.../PromptExecutor.kt:14),实现它的三个组合器就是这一层的精华:
PromptExecutor (抽象)
├─ MultiLLMPromptExecutor provider → 唯一 client 的 map;找不到走 fallback
├─ RoutingLLMPromptExecutor 委托给 LLMClientRouter 选 client(支持负载分发)
└─ (RoundRobinRouter 是路由策略,不是 executor)
resolveModel 是"可切换"的关键钩子。 它接受一个 LLModel、返回一个 ResolvedModel,实现可以中途把请求的模型换成另一个(比如 fallback)。默认实现原样返回(PromptExecutorAPI.kt:94)。
MultiLLMPromptExecutor:一 provider 一 client
构造时给一张 Map<LLMProvider, LLMClient>,外加可选 fallback(prompt-executor-model/.../llms/MultiLLMPromptExecutor.kt:41)。它的 resolveModel 逻辑很直白:
// 示意,非源码:MultiLLM 的模型解析
resolveModel = when {
model.provider in llmClients -> model // 有对口 client,直接用
fallback != null -> fallback.model // 没有,降级到 fallback 模型
else -> throw ModelResolutionException(...) // 都没有,报错
}
真实实现在 MultiLLMPromptExecutor.kt:148(resolveModel);真正发请求时 clientFor(effectiveModel) 按 model.provider 取出 client 并委托(MultiLLMPromptExecutor.kt:191 + :292)。这就是"换模型即换 client"落地的那一行:只要新模型的 provider 在 map 里,同一份 prompt 直接交给新 client 重新编码。
RoutingLLMPromptExecutor + RoundRobinRouter:同 provider 多 client 轮询
当一个 provider 想挂多个 client(多个 API key、多个区域端点做负载分发)时,用 RoutingLLMPromptExecutor(prompt-executor-model/.../llms/RoutingLLMPromptExecutor.kt:40)。它把"选哪个 client"这件事外包给 LLMClientRouter 接口(LLMClientRouter.kt:13,只有 clients 和 clientFor(model) 两个成员)。
默认路由策略是 RoundRobinRouter(prompt-executor-model/.../llms/RoundRobinRouter.kt:19):同一 provider 下多个 client 时,用一个原子计数器取模轮流发。
// 真实逻辑,RoundRobinRouter.kt:68 ClientPool.Multiple.next()
override fun next(): LLMClient =
clients[counter.fetchAndIncrement().mod(clients.size)] // 原子自增取模,线程安全
单 client 时会走 ClientPool.Single 省掉计数(RoundRobinRouter.kt:61)。
3.5 LLMClient:把中立 Prompt 翻译成各家 API
要解决的小问题: OpenAI、Anthropic、Google 的 HTTP 请求体格式各 不相同。统一的 Prompt 必须被翻译成每家能懂的样子。
思路: 每个 provider 一个模块、一个 LLMClient 实现,职责单一:编码请求 + HTTP + 解码响应。
接口 LLMClientAPI 在 prompt-executor-clients/src/commonMain/.../clients/LLMClientAPI.kt:19,和 executor 的方法几乎一一对应(execute/executeStreaming/executeMultipleChoices/moderate/models),外加 llmProvider()(:104)让上层知道"我是哪家"。LLMClient 本体也是 expect abstract class,同时实现 LLMClientAPI 和 embedding 接口(LLMClient.kt:11)。
provider 各自成模块,互不依赖:
模块目录(prompt-executor-clients/ 下) | 厂商 |
|---|---|
prompt-executor-openai-client | OpenAI |
prompt-executor-anthropic-client | Anthropic |
prompt-executor-google-client | Google Gemini |
prompt-executor-bedrock-client | AWS Bedrock |
prompt-executor-ollama-client | Ollama(本地) |
prompt-executor-deepseek-client | DeepSeek |
prompt-executor-openrouter-client | OpenRouter |
prompt-executor-dashscope-client | 阿里 DashScope |
以 OpenAI 为样本看 client 职责。 OpenAILLMClient(prompt-executor-openai-client/.../openai/OpenAILLMClient.kt:107)持有 OpenAIClientSettings(baseUrl、v1/chat/completions 等路径,:88),继承自 AbstractOpenAILLMClient。真正的"编码 → 发 → 解码"三步在抽象基类里:
// 真实逻辑,AbstractOpenAILLMClient.kt:182 execute()
override suspend fun execute(prompt, model, tools): Message.Assistant {
val response = getResponse(prompt, model, tools) // 内部 serializeProviderChatRequest 编码 + HTTP
return processProviderChatResponse(response).first() // 解码回中立 Message.Assistant
}
编码那步 serializeProviderChatRequest(在 streaming 分支可见全貌,AbstractOpenAILLMClient.kt:196)把中立结构一一映射到 OpenAI 字段:messages、tools.map { it.toOpenAIChatTool() }、prompt.params.toolChoice?.toOpenAIToolChoice()、params。换句话说:同 一份 Prompt,换成 Anthropic client 就走另一套 toXxx 映射——历史不用动,这就是"无缝适配"的机械原理。
模型目录 OpenAIModels(prompt-executor-openai-client/.../openai/OpenAIModels.kt:54)是一堆预置的 LLModel 常量(Chat.GPT5、Moderation.Omni 等)。LLModel 本身很小(prompt-llm/.../llm/LLModel.kt:16):provider + id + capabilities + 上下文长度。supports(capability) 用来在发请求前校验能力(LLModel.kt:29),比如流式前 model.requireCapability(LLMCapability.Completion)(AbstractOpenAILLMClient.kt:193)。
3.6 会话入口:节点如何读写这段历史
要解决的小问题: 上面全是"无状态的一次调用"。但 agent 运行时,prompt/model/tools 是会随对话演进的可变状态,还可能被并发访问。谁来守着它?
思路: AIAgentLLMContext 持有这份可变状态,并只暴露两种带锁的访问方式——readSession(读锁,可并发) 与 writeSession(写锁,独占)。节点(02 章那些)一律通过它读写。
Context 的公共逻辑在 agents/agents-core/src/commonMain/.../context/AIAgentLLMContextCommon.kt:22。它用一把 RWLock(非可重入)守着可变的 prompt(:107),并提供:
writeSession { ... }(AIAgentLLMContextCommon.kt:178):拿写锁,建一个AIAgentLLMWriteSession,块结束时把会话里改过的prompt/tools/model写回 context(:196-198)。readSession { ... }(AIAgentLLMContextCommon.kt:216):拿读锁,建只读会话,改动不回写。
writeSession 是 02 章节点的主力入口。 它的方法都在 agents/agents-core/src/commonMain/.../session/AIAgentLLMWriteSessionCommon.kt:
| 方法 | 干什么 | 位置 |
|---|---|---|
appendPrompt { ... } | 用 PromptBuilder 往当前 prompt 追加消息 | :115 |
requestLLM() | 发请求,并把回复 append 回 prompt | :181 |
requestLLMWithoutTools() | 禁用工具后再请求 | :144 |
requestLLMOnlyCallingTools() | 强制只调工具(ToolChoice.Required) | :154 |
requestLLMForceOneTool(tool) | 强制调某个具名工具 | :163 |
requestLLMStreaming() | 流式请求,返回 Flow<StreamFrame> | :191 |
requestLLMStructured(...) | 结构化输出请求(见 3.7) | :207 |
requestLLMMultipleChoices() | 拿多候选回复 | :258 |
requestModeration(...) | 内容审核 | :199 |
changeModel(newModel) | 中途换模型(下一次请求即生效) | :129 |
changeLLMParams(...) / setToolChoice*() | 改参数/工具选择 | :136 / :399 |
replaceHistoryWithTLDR(...) | 压缩历史(具体策略见 05 章) | :465 |
注意一个分工:写会话本身不直接调 executor。它把真正的请求委托给内部的 readSession,再把结果 append 回去。看 requestLLM:
// 真实逻辑,AIAgentLLMWriteSessionCommon.kt:181
public suspend fun requestLLM(): Message.Assistant =
readSession.requestLLM().also { response ->
appendPrompt { message(response) } // 把回复写进历史
}
而 readSession.requestLLM()(AIAgentLLMReadSessionCommon.kt:101)才真正碰 executor:先 preparePrompt(用 config.missingToolsConversionStrategy.convertPrompt 适配工具消息,:69),再 executor.executeProcessed(...)(:85)。requestLLMWithoutTools/requestLLMForceOneTool 等只是在发之前改一下 LLMParams.toolChoice 再走同一条 execute(AIAgentLLMReadSessionCommon.kt:112、:143)。
把"可切换"串起来: 节点在 writeSession 里 changeModel(Claude) 只是把 model 字段改了;下一次 requestLLM() 就带着原封不动的历史 + 新 model 去找 executor,executor 的 resolveModel/clientFor 自动换到对口 client 重新编码。整条链路没有一处需要"转换历史格式"。
3.7 结构化输出、流式、审核(一句话定位)
这三样都挂在同一套 executor/session 上,细节各有模块,这里只给坐标:
- 结构化输出(structured):
requestLLMStructured(serializer)(AIAgentLLMWriteSessionCommon.kt:219)让模型按某个 Kotlin 类型的 JSON schema 回答;底层走executor.executeStructured,schema 生成与校验在prompt-structure模块。schema 也可直接塞进LLMParams.Schema(LLMParams.kt:198,分JSON.Basic/JSON.Standard)。 - 流式(streaming): 返回
Flow<StreamFrame>。StreamFrame是密封类型(prompt-model/.../streaming/StreamFrame.kt:13),分文本(TextDelta/TextComplete)、推理(ReasoningDelta/ReasoningComplete)、工具调用(ToolCallDelta/ToolCallComplete)和收尾End(带 finishReason 与 token 元信息)。 - 审核(moderation):
requestModeration(model)→executor.moderate→ModerationResult。类别体系(ModerationCategory:Harassment/Hate/...)在prompt-model/.../dsl/ModerationAPI.kt:10。
4. 巧妙之处(可借鉴的技术)
-
不可变值 + 拷贝语义治并发。
Prompt/Message全是data class,任何"改"都产生新对象(Prompt.kt:129起)。会话只需在写回那一刻用写锁保护字段替换,而不必锁住整个对话结构——数据本身天然线程安全。 -
两级
expect abstract class把"接口"和"平台实现"解耦。PromptExecutor(PromptExecutor.kt:14)、LLMClient(LLMClient.kt:11)、AIAgentLLMContext(context/AIAgentLLMContext.kt:57)都用这招:公共行为写在...Common基类,平台差异留给actual。文档/调用方只认接口。 -
resolveModel 作为"可插拔的模型替换点"。 把"想要哪个模型"和"实际用哪个"分成两步(
PromptExecutorAPI.kt:94+MultiLLMPromptExecutor.kt:148),fallback、灰度、按操作类型选模型全都塞进这一个钩子,不污染 execute 主流程。 -
写会话委托读会话。 请求逻辑只写一遍在 read session,write session 只加"append 回历史"这层薄壳(
AIAgentLLMWriteSessionCommon.kt:181)——读写行为天然一致,不会漂移。 -
round-robin 用原子取模,零锁轮询。
counter.fetchAndIncrement().mod(size)(RoundRobinRouter.kt:68)在多 key 负载分发下线程安全又便宜。
5. 边界与局限(诚实说明)
-
RWLock 不可重入。 在
writeSession/readSession/withPrompt内部再调其中任意一个(同一 context)会死锁——源码注释反复警告(AIAgentLLMContextCommon.kt:117-119、:169-171)。 -
能力不匹配直接抛。 模型不支持某能力时 client 直接
requireCapability抛异常(如流式,AbstractOpenAILLMClient.kt:193);executeMultipleChoices/executeStreaming在部分 client 上是Not implemented(LLMClientAPI.kt:61、:77)。 -
直接读
prompt不加锁。 在会话外直接读context.prompt/model/tools拿到的是"当前恰好装着的快照",不保证与并发写一致;要一致视图得在readSession里读(AIAgentLLMContextCommon.kt:99-105)。 -
DetachedPromptExecutorAPI是逃生口而非常规路径。 直接从 context 取promptExecutor绕开 agent 逻辑(不走ToolsConversionStrategy、不改 agent 状态),需显式 opt-in(AIAgentLLMContext.kt:29)。 -
本章不覆盖: 工具的 schema 生成与注册(见 04 章)、历史压缩策略的具体实现(
replaceHistoryWithTLDR背后的HistoryCompressionStrategy,见 05 章)。
6. 代码地图(导航索引)
| 主题 | 文件路径 | 关键符号 |
|---|---|---|
| Prompt 数据结构 | prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/Prompt.kt | Prompt、withMessages、withUpdatedParams、latestTokenUsage |
| Message / MessagePart | prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/message/Message.kt | Message、Message.System/User/Assistant、MessagePart.Tool.Call/Result、ResponseMetaInfo |
| PromptBuilder DSL | prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/dsl/PromptBuilder.kt | PromptBuilder、system、user、assistant、build、from |
| prompt() 入口 | prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/dsl/PromptDSL.kt | prompt、emptyPrompt |
| 调用参数 | prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/params/LLMParams.kt | LLMParams、default、Schema、ToolChoice |
| Executor 抽象接口 | prompt/prompt-executor/prompt-executor-model/src/commonMain/kotlin/ai/koog/prompt/executor/model/PromptExecutorAPI.kt | PromptExecutorAPI、execute、resolveModel |
| 多 LLM executor | prompt/prompt-executor/prompt-executor-model/src/commonMain/kotlin/ai/koog/prompt/executor/llms/MultiLLMPromptExecutor.kt | MultiLLMPromptExecutor、resolveModel、clientFor、FallbackPromptExecutorSettings |
| 路由 executor | prompt/prompt-executor/prompt-executor-model/src/commonMain/kotlin/ai/koog/prompt/executor/llms/RoutingLLMPromptExecutor.kt | RoutingLLMPromptExecutor |
| 轮询路由 | prompt/prompt-executor/prompt-executor-model/src/commonMain/kotlin/ai/koog/prompt/executor/llms/RoundRobinRouter.kt | RoundRobinRouter、ClientPool |
| 路由接口 | prompt/prompt-executor/prompt-executor-model/src/commonMain/kotlin/ai/koog/prompt/executor/llms/LLMClientRouter.kt | LLMClientRouter、clientFor |
| Client 接口 | prompt/prompt-executor/prompt-executor-clients/src/commonMain/kotlin/ai/koog/prompt/executor/clients/LLMClientAPI.kt | LLMClientAPI、llmProvider |
| OpenAI client(样本) | prompt/prompt-executor/prompt-executor-clients/prompt-executor-openai-client/src/commonMain/kotlin/ai/koog/prompt/executor/clients/openai/OpenAILLMClient.kt | OpenAILLMClient、OpenAIClientSettings |
| OpenAI 编解码 | prompt/prompt-executor/prompt-executor-clients/prompt-executor-openai-client-base/src/commonMain/kotlin/ai/koog/prompt/executor/clients/openai/base/AbstractOpenAILLMClient.kt | execute、serializeProviderChatRequest、processProviderChatResponse |
| OpenAI 模型目录 | prompt/prompt-executor/prompt-executor-clients/prompt-executor-openai-client/src/commonMain/kotlin/ai/koog/prompt/executor/clients/openai/OpenAIModels.kt | OpenAIModels |
| LLModel | prompt/prompt-llm/src/commonMain/kotlin/ai/koog/prompt/llm/LLModel.kt | LLModel、supports |
| 会话 context | agents/agents-core/src/commonMain/kotlin/ai/koog/agents/core/agent/context/AIAgentLLMContextCommon.kt | AIAgentLLMContextCommon、writeSession、readSession、withPrompt |
| 写会话 | agents/agents-core/src/commonMain/kotlin/ai/koog/agents/core/agent/session/AIAgentLLMWriteSessionCommon.kt | appendPrompt、requestLLM、changeModel、replaceHistoryWithTLDR |
| 读会话 | agents/agents-core/src/commonMain/kotlin/ai/koog/agents/core/agent/session/AIAgentLLMReadSessionCommon.kt | requestLLM、preparePrompt、requestLLMStructured |
| 流式帧 | prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/streaming/StreamFrame.kt | StreamFrame、TextDelta、ToolCallComplete、End |
| 审核 | prompt/prompt-model/src/commonMain/kotlin/ai/koog/prompt/dsl/ModerationAPI.kt | ModerationCategory、ModerationResult |
同组其它章: index · 01 图执行引擎 · 02 构建层 · 04 工具系统 · 05 Feature 与运行时扩展