Skip to content

Chapter 4 · Model Configuration and Instruction Design ​

Chapter goals: Master the declarative usage of useModel() and model identifier format, learn to tune with thinkingLevel and compaction, and understand the "upgrade"模式 of dynamic model switching.

4.1 useModel(): Declarative, Not Client-Side ​

useModel() is Flue's only required Hook, but it returns nothing and creates no SDK client — you only "name" the model; connection, auth, streaming, and retry are all handled by the Flue runtime:

typescript
'use agent';
import { useModel } from '@flue/runtime';

export function TriageAgent() {
  // You don't need new Anthropic(), no API key passing, no retry handling
  useModel('anthropic/claude-sonnet-4-6');
  return 'Investigate the reported issue and recommend the next action.';
}

Two hard rules:

  1. Must be called: an agent without useModel() cannot start rendering;
  2. Called exactly once per render: parameters can change, but the call itself must not disappear or duplicate.

Exception: sub-agents

Sub-agents cannot call useModel() in their render — their model is specified on the useSubagent() definition; if unspecified, they inherit the parent agent's model.

4.2 Model Identifier Format ​

The model identifier is a plain string in 'provider-id/model-id' format. Everything before the first / is the Provider ID; everything after is the provider's own model ID (which may itself contain slashes):

typescript
// Standard provider/model form
useModel('anthropic/claude-sonnet-4-6');
useModel('openai/gpt-5.5');

// When the model ID itself contains slashes — the first / is the delimiter
useModel('openrouter/moonshotai/kimi-k2.6');      // openrouter's moonshotai/kimi-k2.6
useModel('cloudflare/@cf/moonshotai/kimi-k2.6');  // Cloudflare Workers AI, no API key needed

Built-in Providers come from Pi's full directory: anthropic, openai, google, amazon-bedrock, google-vertex, groq, mistral, xai, deepseek, cerebras, together, fireworks, openrouter, etc. The directory metadata includes context window size, output cap, rate, reasoning support, and input modalities — these determine compaction trigger timing and whether thinkingLevel takes effect.

Unknown models fail fast: the request errors before being sent, identifying the unresolved provider and model ID.

4.3 thinkingLevel and compaction Tuning ​

The second optional parameter provides two fields:

typescript
'use agent';
import { useModel } from '@flue/runtime';

export function DeepResearcher() {
  useModel('anthropic/claude-opus-4-6', {
    // Reasoning depth: off | minimal | low | medium (default) | high | xhigh | max
    thinkingLevel: 'high',
    // Auto-compaction config
    compaction: {
      reserveTokens: 30000,        // Threshold margin (default model-aware, ≤20000)
      keepRecentTokens: 16000,     // Recent history preserved verbatim (default 8000)
      model: 'anthropic/claude-haiku-4-5', // Cheaper model for summarization
    },
  });
  return 'Conduct deep research on the given topic and produce a structured report.';
}

Key points:

  • thinkingLevel is a default — individual operations can override (sub-agent definitions, harness.prompt() calls);
  • Thinking content is only sent live for reasoning-capable models;
  • compaction: false disables threshold auto-compaction (overflow recovery still has fallback).

When a conversation approaches the model's context limit, Flue automatically folds old history into a summary while keeping recent messages verbatim — the session continues seamlessly.

4.4 Dynamic Model Switching: The Cost Upgrade Pattern ​

Because rendering happens every round, the model identifier can be computed from state. The classic pattern is "upgrade": cheap model for daily work, strong model for complex tasks:

typescript
'use agent';
import { useModel, usePersistentState } from '@flue/runtime';

export function Reviewer() {
  // escalated is a cross-round persistent flag
  const [escalated, setEscalated] = usePersistentState('escalated', false);

  // State determines which model this round uses — re-evaluated on each render
  useModel(escalated
    ? 'anthropic/claude-opus-4-6'
    : 'anthropic/claude-haiku-4-5');

  return `
Review the code changes submitted by the user.
If you find a complex defect requiring deep推理,
first use the escalate tool to set escalated to true, then continue analysis.`;
}

Paired with tools (Chapter 6) that let the model self-decide when to upgrade, you achieve a "cheap model does grunt work + strong model tackles hard problems" cost-optimized组合.

4.5 Writing High-Quality Instructions ​

The quality of the returned string directly determines the agent's ceiling. Four principles:

typescript
'use agent';
import { useModel } from '@flue/runtime';

export function CodeReviewer() {
  useModel('anthropic/claude-sonnet-4-6');
  return `
You are a senior code reviewer. Follow this流程 when reviewing PRs:
1. Read the change description first to understand intent;
2. Use grep to locate affected core logic, read surrounding context;
3. Classify issues by severity: blocker / suggestion / nit;
4. Output format: one paragraph per issue, with file and line number, plus fix suggestion.`;
}

Four principles: 定角色 (who you are), 划流程 (step-by-step reasoning path), 给格式 (output structure), 设红线 (what not to do).

4.6 Chapter Summary ​

  • useModel() is declarative — Flue handles connections, auth, streaming, retries;
  • Model identifiers: 'provider-id/model-id' format; first / is the delimiter;
  • thinkingLevel controls reasoning depth; compaction controls auto-summarization behavior;
  • Dynamic model switching: compute the model string from state on each render;
  • High-quality instructions: define role, flow, format, and red lines.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. What does useModel() do inside a Flue agent?

2. What is the correct model identifier format in Flue?

3. What happens when compaction kicks in during a long conversation?

4. Why can the model identifier be computed dynamically from state?

🛠️ Hands-On Exercises ​

  1. Write an agent that uses thinkingLevel: 'high' for a reasoning task and compares output quality vs thinkingLevel: 'off' on the same prompt.
  2. Implement the "upgrade" pattern from Section 4.4: start with haiku, escalate to opus when a complex defect is detected; verify the model switch actually occurs.
  3. Set compaction: false and observe what happens when the conversation exceeds the context window — does the overflow fallback still work?

Models configured. Next, learn session and context management.