LLM 包¶
github.com/ktsoator/or/llm 提供统一的 Go API,用于在 OpenAI 兼容与 Anthropic 兼容的模型之间进行流式响应、结构化工具、推理内容、多模态消息和对话历史的处理。
它是什么¶
本包是一个无状态的翻译层。对每个请求,它只决定在网络上发送什么、以及如何解释流式返回的响应——仅此而已。同一段协议无关的对话可以发给任一协议下的任一模型,且目标模型可以在轮次之间切换;库会每次重新适配历史。
单个请求之上的一切(历史存储、上下文压缩、工具调用循环)都交给调用方。请求本身由两个入口覆盖:
Complete发送一段对话并返回最终的AssistantMessage。Stream返回一个类型化Event的通道,用于增量渲染。
flowchart LR
subgraph caller["你的代码"]
direction TB
ctx["Context<br/><small>系统提示 · 消息 · 工具</small>"]
opts["StreamOptions<br/><small>key · temperature · 推理</small>"]
model["Model<br/><small>协议 · 端点</small>"]
end
subgraph lib["llm · 无状态翻译层"]
direction TB
entry(["Stream / Complete"])
adapt["按 Model.Protocol 选适配器<br/><small>重新适配历史 → 线格式</small>"]
entry --> adapt
end
provider["Provider<br/><small>OpenAI 或 Anthropic 兼容</small>"]
subgraph back["返回给你"]
direction TB
events["类型化 Events<br/><small>文本 · 推理 · 工具调用增量</small>"]
final(["AssistantMessage<br/><small>内容 · 停止原因 · 用量+成本</small>"])
events --> final
end
caller --> entry
adapt -->|请求| provider
provider -->|流式响应| events
classDef accent stroke:#6366f1,stroke-width:2px;
class entry,final accent;
第一个请求¶
解析一个模型、发送提示、读取回复。空导入完成协议注册;当 StreamOptions 未填 key 时,它从该 provider 的环境变量读取。
import (
"github.com/ktsoator/or/llm"
_ "github.com/ktsoator/or/llm/openai" // 注册 OpenAI 兼容协议
)
model := llm.GetModel("deepseek", "deepseek-v4-flash")
msg, err := llm.Complete(ctx, model,
llm.Prompt("Explain Go channels briefly."),
llm.StreamOptions{})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Text()) // 答案
fmt.Println(msg.Usage.Cost.Total) // 花了多少
fmt.Println(msg.StopReason) // 为何停止
若要边生成边渲染,改用 Stream 并消费增量:
events, err := llm.Stream(ctx, model, llm.Prompt("Write a haiku about Go."), llm.StreamOptions{})
if err != nil {
log.Fatal(err)
}
for event := range events {
if event.Type == llm.EventTextDelta {
fmt.Print(event.Delta)
}
}
能力速览¶
- 两种协议,一套 API:OpenAI 兼容的 Chat Completions 与 Anthropic 兼容的 Messages,共用同一套类型。
- 流式事件:文本、推理与工具调用增量以类型化事件呈现,每个都带有到目前为止的消息部分快照。
- 类型化工具:从 Go 结构体派生 JSON Schema,并把模型的调用解码回该结构体,对畸形参数尽力恢复。
- 协议无关的推理:单一强度等级映射到各 provider 的原生思考,并钳制到模型支持的范围。
- 多模态输入:图像可与文本并存,对纯文本模型自动降级。
- 用量与成本:每个响应按目录计价的 token 计数,含缓存 token。
- 切换模型:把一段历史发给任意模型或协议,无需重建;库会每次请求重新适配。
- 持久化:消息序列化为自描述 JSON,之后可对任意模型重放。
- 可扩展:实现一个适配器即可加入新的线协议,无需改动共享的请求 API。
核心对象¶
五个类型几乎涵盖日常会用到的一切:
| 类型 | 作用 |
|---|---|
Model |
调用哪个模型——用 GetModel 从目录解析,或手动构造以指向任意兼容端点 |
Context |
单次请求的输入:系统提示、消息历史、可用工具 |
Message |
历史中的一轮——UserMessage、AssistantMessage 或 ToolResultMessage,各自持有类型化内容块 |
StreamOptions |
按请求的设置:凭证、temperature、max tokens、推理强度、超时与钩子 |
AssistantMessage |
结果:内容、停止原因、带成本的 token 用量,以及诊断 |
常见路径¶
按手头的任务挑选指南:
- 一次请求:用
Prompt构造Context,调用Complete。见快速开始。 - 多轮:维护一个不断增长的
[]Message,每轮重新发送。见对话。 - 流式:调用
Stream,边到达边消费Event增量。见流式。 - 工具:定义类型化工具并运行工具循环。见工具。
- 推理:设置推理强度并读回思考。见推理。
- 切换模型:把同一段历史发给不同模型或协议。见对话 § 在不同轮次间切换模型。
选 llm 还是 agent?¶
在自行掌控控制流时直接用 llm:单次请求、自定义的多轮循环,或需要完全掌控的工具循环。当希望工具调用循环、运行状态、引导与中止由框架代劳时,选or/agent;当还需要转录持久化、上下文压缩、按轮系统提示与 skills 时,选 agent harness。两者都构建在上述类型之上,所以先用 llm、之后再采用 agent,不会有任何浪费。
安装¶
文档¶
- 快速开始 — 凭证与第一个请求
- 提供方与模型 — 目录发现与自定义端点
- 流式 — 事件、部分响应、诊断与取消
- 工具 — 类型化工具、工具循环与协议特定的工具选择
- 推理 — 推理强度与思考显示
- 读取响应 — 停止原因、用量与成本、诊断
- 错误处理 — 错误出口、缺失密钥与校验
- 对话 — 图像、模型切换与持久化
- 配置 — 重试、超时、请求头与 HTTP 钩子
- 自定义协议 — 适配器、注册表与
StreamWriter
每个主题的可运行程序列在示例页。
完整的导出类型和函数,参见pkg.go.dev 上的包文档。
若想了解本包的内部工作原理(消息转换、模型目录与适配器层)参见内部实现指南。