模型
每个智能体同时只由一个 LLM 驱动,通过 useModel() 声明——这是 Flue 中唯一的必需 hook。本指南涵盖选择模型、调优调用方式、更改何时生效、提供提供商凭据,以及连接 Flue 开箱即用不认识的提供商。
声明模型
在你的智能体函数体内使用模型说明符字符串调用 useModel():
'use agent';
import { useModel } from '@flue/runtime';
export function TriageAgent() {
useModel('anthropic/claude-sonnet-4-6');
return '调查报告的问题并推荐下一步操作。';
}useModel() 是一个声明,而非客户端:它不返回任何东西,你永远不需要构造 SDK 对象或通过智能体代码传递 API 密钥。你命名模型;Flue 拥有连接、认证、流式传输和重试。
两条规则:
- 该调用是必需的。 没有
useModel()调用的智能体渲染无法启动。 - 每次渲染只调用一次。 一个智能体有一个模型。参数 可以在不同渲染之间变化(更多内容见下文),但调用本身不能消失或重复。
该调用可以放在智能体体内或体内的自定义 hook 中。唯一不能使用的地方是子智能体渲染——委托的模型在其 useSubagent() 定义上设置,未设置时继承父模型。参见子智能体。
模型说明符
模型说明符是 'provider-id/model-id' 格式的纯字符串。第一个 / 之前的所有内容命名提供商;其余是提供商自己的模型 ID,其中可能包含斜杠:
anthropic/claude-sonnet-4-6——提供商anthropic,模型claude-sonnet-4-6openai/gpt-5.5——提供商openai,模型gpt-5.5openrouter/moonshotai/kimi-k2.6——提供商openrouter,模型moonshotai/kimi-k2.6cloudflare/@cf/moonshotai/kimi-k2.6——提供商cloudflare,模型@cf/moonshotai/kimi-k2.6
Flue 根据运行时注册的提供商解析说明符。默认情况下,这是来自 Pi 的完整内置集合,包含了主要提供商——anthropic、openai、google、amazon-bedrock、google-vertex、groq、mistral、xai、deepseek、cerebras、together、fireworks、openrouter 等。每个提供商的目录条目包含模型的线协议、端点、上下文窗口大小、输出令牌限制、费用率、推理支持和接受的输入模态。该元数据决定了压缩何时触发、思考级别是否到达线路,以及模型是否可以接受图像。
要只包含你实际使用的提供商,在 flue() 插件配置中列出它们——生成的服务器入口随后只导入这些工厂,其他任何内容都不会进入构建:
flue({ providers: ['anthropic', 'openai'] });设置了 providers 列表后,命名任何其他提供商的说明符在解析时会失败——该列表是穷尽的,因此在 Cloudflare 目标上,当你的智能体使用 cloudflare/... 模型时,请包含 'cloudflare'。省略该字段以保留完整集合。参见提供商 API 参考了解确切语义。
未知的说明符会快速失败:运行在发送任何请求之前就因未解析的提供商和模型 ID 而报错。要教会 Flue 一个内置提供商不服务的说明符——本地模型、代理、全新发布——请自行注册提供商;参见自定义提供商。
在 Cloudflare 目标上,还有一个额外的内置提供商 ID:cloudflare/... 模型说明符在 Workers AI 上运行,完全不需要 API 密钥。
模型推理强度
useModel() 接受一个选项对象作为第二个参数,包含两个字段:thinkingLevel 和 compaction。
useModel('anthropic/claude-opus-4-6', {
thinkingLevel: 'high',
compaction: { keepRecentTokens: 16000 },
});
thinkingLevel 设置智能体模型调用的默认推理强度:'off'、'minimal'、'low'、'medium'、'high'、'xhigh' 或 'max'。未设置时,运行时使用 'medium'。
更高的级别以延迟和令牌为代价增加推理深度;'off' 完全禁用扩展思考。该值是_默认值_:个别操作可以覆盖它——子智能体定义可以固定自己的 thinkingLevel,编程式的 harness.prompt(...) 调用接受每次操作一个。
思考只对标记为支持推理的模型到达线路。目录模型已携带该标志,但如果你注册自定义提供商并跳过其 reasoning 元数据,转发的 thinkingLevel 会被静默丢弃。参见自定义提供商。
压缩
智能体对话可能比任何上下文窗口都长。当对话接近模型的限制时,Flue 自动压缩它:较旧的历史被折叠成摘要,而最近的消息保持原文,对话继续。compaction 选项调优该行为:
useModel('anthropic/claude-opus-4-6', {
compaction: {
// 提前或延后触发:当已用令牌超过 contextWindow - reserveTokens 时运行压缩。
// 默认:模型感知,≤ 20000。
reserveTokens: 30000,
// 多少最近的历史保持原文。默认:8000。
keepRecentTokens: 16000,
// 使用比会话运行的模型更便宜的模型进行摘要。
model: 'anthropic/claude-haiku-4-5',
},
});
所有三个字段都是可选的;每个都覆盖模型感知的默认值。设置 compaction.model 将摘要卸载到更便宜的模型。
传递 compaction: false 禁用_阈值_压缩——自动触发器。溢出恢复和显式的 harness.compact() 调用在对话不再适合时仍然会压缩。完整的字段参考在 CompactionConfig。
在对话中途更改模型
智能体函数在每次模型调用之前重新渲染,useModel() 每次都会再次运行——因此说明符可以是计算的,而非常量。一个常见的模式是升级,其中持久状态将智能体从便宜的模型移到强大的模型:
'use agent';
import { useModel, usePersistentState, useTool } from '@flue/runtime';
export function Reviewer() {
const [escalated, setEscalated] = usePersistentState('escalated', false);
useModel(escalated ? 'anthropic/claude-opus-4-6' : 'anthropic/claude-haiku-4-5');
useTool({
name: 'escalate_review',
description: '当更改太复杂无法快速审查时升级。',
async run() {
setEscalated(true);
return '已升级。更强的模型将接手。';
},
});
return '审查提议的更改并留下可操作的反馈。';
}模型、思考级别和压缩设置是提交范围的:运行时在智能体唤醒以处理已接受的输入(一次_提交_——参见持久性)时读取它们一次。运行中途重新渲染计算的不同值会锁存并在_下一次_提交时生效,而非在当前提交的中途。在上面的例子中,触发 escalate_review 的响应在便宜的模型上完成;对话的下一条消息在强大的模型上运行。
dispatch(...) 或 HTTP 接口上没有每消息的模型参数:模型选择属于智能体函数。
提供商凭据
模型提供商通过 API 密钥认证,运行时从环境解析它们——你的智能体代码永远不处理它们。
本地开发
将密钥放在项目根目录的 .env 文件中,使用每个提供商期望的变量名:
ANTHROPIC_API_KEY="sk-ant-..."
OPENAI_API_KEY="sk-..."
GEMINI_API_KEY="..."anthropic 读取 ANTHROPIC_API_KEY,openai 读取 OPENAI_API_KEY,google 读取 GEMINI_API_KEY,groq 读取 GROQ_API_KEY——该模式在所有提供商中适用(参见 Pi 的提供商文档 了解完整列表)。两个本地入口点都为你加载文件,shell 导出的值始终优先于文件值:
flue run加载项目根目录的.env;传递--env <path>选择一个替代文件。vite dev加载 Vite 的标准文件集:.env、.env.local、.env.<mode>、.env.<mode>.local。
不要提交 .env 文件。
部署环境
部署后的服务器只读取真实环境——没有 .env 加载:
- Node.js ——通过主机的密钥机制将密钥作为进程环境变量提供。参见 Node.js 目标——环境和密钥。
- Cloudflare ——将每个密钥添加为 Worker 密钥(
npx wrangler secret put ANTHROPIC_API_KEY);在本地,.dev.vars扮演.env的角色。参见 Cloudflare 部署指南。
当环境变量约定不适合时——一个有自己凭据的网关、一个在代码中给你值的密钥管理器——在自定义提供商上声明凭据:提供商的 auth.apiKey.resolve() 返回你的代码产生的任何东西,并且它每次请求运行,因此轮换凭据也可以工作。
自定义提供商
提供商是 Pi 自己的对象,Flue 直接接受它们:用 Pi 的 createProvider()(或任何提供商工厂)构建一个,并在 app.ts 的模块顶层、任何智能体运行之前交给 setProvider()。由于你的代码现在直接导入 Pi,请将其添加到项目的依赖中:npm install @earendil-works/pi-ai。注册按提供商的 id 键控,每次调用替换该 ID 的先前提供商——包括内置的,因此覆盖 anthropic 只需在该 ID 下注册你自己的提供商。一个放置注意事项:flue run 只加载智能体模块,不加载 app.ts——当智能体也必须在 flue run 下工作时,请将注册放在智能体模块中。
任何 OpenAI 或 Anthropic 兼容的端点都可以工作。这是一个本地 Ollama 服务器:
import { createProvider, envApiKeyAuth } from '@earendil-works/pi-ai';
import { openAICompletionsApi } from '@earendil-works/pi-ai/api/openai-completions.lazy';
import { setProvider } from '@flue/runtime';
setProvider(
createProvider({
id: 'ollama',
// 无密钥本地服务器;使用 envApiKeyAuth('...', ['MY_KEY']) 处理真实密钥。
auth: { apiKey: { name: 'Ollama (keyless)', resolve: async () => ({ auth: {} }) } },
models: [
{
id: 'llama3.1:8b',
name: 'Llama 3.1 8B (local)',
api: 'openai-completions',
provider: 'ollama',
baseUrl: 'http://localhost:11434/v1',
reasoning: false,
input: ['text'],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 8192,
},
],
api: openAICompletionsApi(),
}),
);useModel('ollama/llama3.1:8b');提供商声明其模型,运行时信任该元数据:reasoning: false 意味着 thinkingLevel 被静默丢弃,input: ['text'] 意味着附加的图像被替换为”(image omitted)“占位符,contextWindow: 0 读作未知,因此阈值压缩无法启用。
将内置提供商路由到网关或代理是同样的操作——在内置的 ID 下注册你自己的提供商,用你的端点和凭据复用其目录模型:
import { createProvider } from '@earendil-works/pi-ai';
import { anthropicMessagesApi } from '@earendil-works/pi-ai/api/anthropic-messages.lazy';
import { anthropicProvider } from '@earendil-works/pi-ai/providers/anthropic';
import { setProvider } from '@flue/runtime';
setProvider(
createProvider({
id: 'anthropic',
auth: {
apiKey: {
name: 'Gateway key',
resolve: async () => ({ auth: { apiKey: process.env.GATEWAY_KEY } }),
},
},
models: anthropicProvider()
.getModels()
.map((model) => ({ ...model, baseUrl: 'https://gateway.example.com/anthropic' })),
api: anthropicMessagesApi(),
}),
);智能体的说明符(anthropic/claude-sonnet-4-6)不会改变;费用、上下文窗口和能力元数据从目录中随行。当你需要时,Pi 的提供商协议可以走得更远——OAuth、动态模型发现、通过 api 字段的自定义线协议——所有内容都记录在 Pi 的提供商指南 中。Flue 自己的契约在提供商 API 参考中。
Cloudflare Workers AI(仅限 Cloudflare)
在 Cloudflare 目标上,cloudflare 提供商 ID 会自动注册,并在 Workers AI 上运行模型——无需 API 密钥,无需外部账户;授权和计费跟随 Worker,包括 Workers AI 定价和每日免费配额:
export function Assistant() {
useModel('cloudflare/@cf/moonshotai/kimi-k2.6');
return '帮助用户解决他们的问题。';
}在项目的 Wrangler 配置中声明提供商使用的 AI 绑定:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"ai": {
"binding": "AI",
},
}cloudflare/ 之后的所有内容作为模型 ID 传递给 env.AI.run(...)。这可以是 Workers AI 模型 ID(如 @cf/moonshotai/kimi-k2.6),或绑定支持的 AI Gateway 模型 ID(如 openai/gpt-5.5),当 Worker 应通过 Cloudflare 的网关路径访问该模型时——cloudflare/openai/gpt-5.5 通过 Cloudflare 计费,而纯 openai/gpt-5.5 使用 Flue 的直接 OpenAI 提供商及其 API 密钥。
默认情况下,每个 cloudflare/... 调用都通过 Cloudflare 的 AI Gateway 路由,在仪表板中开箱即用地提供缓存、日志记录和预算控制。要定向到特定的网关、调优缓存和日志记录,或选择退出,请在 app.ts 中自行注册 cloudflare 提供商——你的注册优先于生成的默认值:
import { setProvider } from '@flue/runtime';
import { cloudflareBindingProvider } from '@flue/runtime/cloudflare/workers-ai';
import { env } from 'cloudflare:workers';
setProvider(
cloudflareBindingProvider({
binding: env.AI,
gateway: { id: 'my-gateway', cacheTtl: 300, metadata: { tenant: 'acme' } },
// ...或 gateway: false 完全绕过 AI Gateway。
}),
);Cloudflare 的模型接口也可以从任何目标通过两个普通目录提供商访问:cloudflare-workers-ai/...(URL 支持的 Workers AI)和 cloudflare-ai-gateway/...(URL 支持的 AI Gateway),两者都像其他托管提供商一样用 CLOUDFLARE_API_KEY 认证。参见 Cloudflare 目标指南 了解目标的完整模型故事。
后续步骤
- 智能体 Hooks API ——完整的
useModel()契约、ThinkingLevel和CompactionConfig。 - 提供商 API ——
providers配置、setProvider()和cloudflareBindingProvider()。 - 子智能体 ——为委托提供自己的模型和思考级别。
- 持久性 ——什么是提交以及中断的模型工作如何恢复。
- 可观测性 ——检查模型调用、令牌使用和提供商诊断。