LLM 调用系统
LLM 系统是 OpenCode 中 AI 执行的核心引擎,负责协调 LLM 提供商、流式处理工具调用和响应解析。
概述
LLM 系统是 OpenCode 的核心执行引擎,它:
- 与多个 LLM 提供商集成(Anthropic、OpenAI 等)
- 管理流式响应(Delta 事件)
- 执行工具和权限检查
- 处理推理内容(Chain of Thought)
- 管理 Token 使用和成本追踪
- 支持重试和错误恢复
定义位置
packages/opencode/src/session/llm.ts(~500+ 行)
核心架构
主要组件
1. StreamInput
定义:packages/opencode/src/session/llm.ts:33-44
export type StreamInput = {
user: MessageV2.User
sessionID: string
model: Provider.Model
agent: Agent.Info
system: string[]
abort: AbortSignal
messages: ModelMessage[]
small?: boolean
tools?: Record<string, boolean>
retries?: number
}
用途:
- �用户输入和会话信息
- 模型和提供商配置
- Agent 和权限信息
- 消息历史和工具配置
2. stream() 主函数
定义:packages/opencode/src/session/llm.ts:48-200+
功能:
- 初始化 Provider 配置
- 构建 System Prompt
- 调用 LLM 提供商
- 处理流式响应(Delta 事件)
- 执行工具调用
- 创建和更新消息 Parts
- 处理错误和重试
流式处理
Delta 事件处理
LLM 通过 Delta 事件处理流式响应:
支持的事件类型:
| 事件类型 | 说明 | 处理 |
|---|---|---|
text-delta | 文本增量更新 | 追加到当前 TextPart |
reasoning-delta | 推理增量更新 | 追加到当前 ReasoningPart |
message-start | 消息开始 | 创建新消息开始标记 |
message-end | 消息结束 | 完成当前消息 |
流程:
- 初始化空状态
- 收集所有 Delta 事件
- 根据 Delta 类型更新内容
- 在
message-end时完成消息
工具执行机制
LLM 系统处理工具调用:
流程:
Token 管理
Token 统计:
- Input: 输入 Token 数
- Output: 输出 Token 数
- Reasoning: 推理 Token 数
- Cache.read: 缓存读取的 Token 数
- Cache.write: 缓存写入的 Token 数
成本追踪:
- 每次调用成本:输入成本 * 输出成本
- 累计成本:会话总成本
- 成本上限:可配置的最大成本
错误处理和重试
自动重试条件
- API 错误且可重试
- 重试次数未超过限制
- 错误是暂存错误(如 429 Too Many Requests)
错误类型
- APIError:提供商 API 错误
- OutputLengthError:输出长度超出
- AbortError:操作被中止
- AuthError:认证失败
提供商集成
支持的提供商
| 提供商 | 支持的功能 |
|---|---|
| Anthropic | Claude 模型,原生支持推理 |
| OpenAI | GPT 模型 |
| 其他 | 通过 OpenAI SDK �集成的提供商 |
系统提示词
Agent 提示词
不同 Agent 可以配置不同的系统提示词,影响 AI 行为。
提供商选项
通过 Provider Transform 配置:
- 温度(temperature)
- Top-P(topP)
- 模型选择
- 超大输出 Token 限制
- 其他提供商特定选项
消息过滤
在将消息传递给 LLM 前:
- 非压缩消息(减少 Token 使用)
- 过滤太旧的消息
- 保留关键上下文
- 限制消息数量
相关文档
- MessageV2 - 消息系统
- Prompt - 提示词系统
- Tool - 工具系统
- Permission - 权限系统
- Provider/Model - 模型和提供商
实现特点
1. 流式响应
使用 Delta 事件实现高效的流式更新,减少延迟。
2. 灪并工具执行
可以执行多个工具调用,LLM 会协调执行。
3. 轻动错误恢复
自动检测可重试的错误并重新发起请求。
4. 灪活事件驱动
通过事件总线与消息系统深度集成。
5. 多提供商支持
统一的接口支持多个 LLM 提供商。
典型使用场景
场景 1:基本对话
// 用户发送消息
const result = await LLM.stream({
user: userMessage,
model: {
providerID: "anthropic",
modelID: "claude-3-5-sonnet",
},
agent: "general",
sessionID: session.id,
})
console.log(result.messages) // AI 的响应消息
场景 2:使用特定 Agent
const result = await LLM.stream({
user: userMessage,
model: {...},
agent: "code-reviewer", // 使用 code-reviewer Agent
sessionID: session.id,
})
场景 3:禁用特定工具
const result = await LLM.stream({
user: userMessage,
model: {...},
agent: "general",
tools: {
"bash": false, // 禁用 bash 工具
},
sessionID: session.id,
})
场景 4:设置系统提示词
const result = await LLM.stream({
user: userMessage,
model: {...},
system: [
"You are an expert at debugging code.",
"Focus on identifying root causes.",
],
sessionID: session.id,
})
设计模式
职责分离
- LLM 系统:流式响应、工具协调
- Prompt 系统:提示词生成
- Tool 系统:工具执行和权限检查
- Permission 系统:权限评估
松耦合
通过清晰的接口和事件系统实现:
- 模块可以独立发展和测试
- 提供商可以灵活替换
- 工具可以动态注册
性能优化
- Delta 事件减少网络延迟
- 消息压缩降低 Token 使用
- Token 缓存减少重复成本
- 异步工具执行提高并发性