LLM Integration¶
APE uses LangChain as its model abstraction
layer. Any BaseChatModel implementation works as the solver backend.
Choosing a provider¶
The [model] config section picks the provider and model name:
provider is a fully-qualified dotted path to a LangChain chat model class.
name becomes its model= constructor argument. Install the matching
LangChain integration package and set the required API key before running:
| Provider | Package | Key env var |
|---|---|---|
| Mistral | langchain-mistralai |
MISTRAL_API_KEY |
| OpenAI | langchain-openai |
OPENAI_API_KEY |
| Anthropic | langchain-anthropic |
ANTHROPIC_API_KEY |
langchain-google-genai |
GOOGLE_API_KEY |
APE loads a .env file automatically if one exists in the project root or any
of its parent directories, so you can keep keys out of shell history.
The solve workflow¶
Each solver session runs a LangGraph workflow. The graph drives the model through a loop until it produces a parsable answer or hits a limit:
START
│
▼
think ◄──────────────────────────────────────────────────┐
│ │
▼ │
route │
├─ tool calls pending ─────────────────────► use_tools ─┘
│ │ ▲
│ └─► context near limit ──► compact_context ─┘
│
├─ no tool calls ───────────────► adapt_solution ──► END
│ ▲
└─ max_steps reached ──► force_finish ─┘
think — invokes the model with the current message history and appends its reply.
route — decides what comes next. The conditions are checked in this order, so earlier ones take precedence:
- If
max_stepshas been reached, go toforce_finish(any pending tool calls are resolved first so the model provider stays happy). - Otherwise, if the model produced a plain text reply (no tool calls), go to
adapt_solution. - Otherwise (tool calls pending), if the context is at or above the compaction
threshold, go to
compact_contextfirst. - Otherwise, go to
use_tools.
use_tools — executes all pending tool calls and appends their outputs.
force_finish — sends a prompt asking the model to produce a final answer
immediately (tool calls are disabled for this turn). The session then proceeds
to adapt_solution, which parses the forced answer like any other, so the
outcome can be Ok(solution), PARSING_FAILED, or GAVE_UP (if the forced
answer still contains I_GIVE_UP).
adapt_solution — passes the last model message to the SolutionAdapter.
On failure it sends the reformat_prompt and retries, up to
solution_adaption_attempts total attempts. If the model output contains
the literal string I_GIVE_UP at any attempt, the session ends with GAVE_UP
immediately.
Context compaction¶
When the conversation grows long, APE compacts it automatically rather than
truncating or failing. The workflow estimates context occupancy using the
o200k_base (GPT-4o/GPT-5) tokenizer as a provider-neutral approximation.
Token counts include both message history and tool schemas.
When occupancy reaches context_compaction_threshold (default 0.8), APE
summarizes the history into a single message and continues the session:
[solver]
context_window_size = 131072 # set manually if auto-detection fails
context_compaction_threshold = 0.75 # trigger earlier
If context_window_size is not set, APE tries to read it from the model's
LangChain profile and falls back to 256 000 tokens.
Helper LLM¶
A second, cheaper model can handle tasks that do not require the full solver:
context compaction and long tool-error summarization. Set it in the [model]
section:
[model]
provider = "langchain_openai.ChatOpenAI"
name = "gpt-4.1"
helper_provider = "langchain_openai.ChatOpenAI"
helper_name = "gpt-4.1-mini"
If no helper is configured, the main model handles these tasks too.
System prompt¶
Every session starts with a built-in system prompt that sets general expectations for the solver. You can extend it without replacing it:
The value can be either a file path (relative to the config) or an inline string. The user prompt is appended to the built-in one.
Rate limits and retries¶
LLM calls are retried automatically when they fail. The
rate_limit_backoff_seconds tuple sets the wait time before each attempt;
its length is also the total number of attempts per call:
If all attempts fail, the session ends with INTERNAL_ERROR.
Key solver parameters¶
| Parameter | Default | Effect |
|---|---|---|
max_steps |
5 |
Think steps allowed before force-finish |
solution_adaption_attempts |
3 |
Parse attempts before PARSING_FAILED |
context_window_size |
auto | Tokens available in the context window |
context_compaction_threshold |
0.8 |
Fraction that triggers compaction |
error_summarization_threshold |
500 |
Min chars in a tool error to trigger summarization |
rate_limit_backoff_seconds |
[2,4,8,16,32] |
Retry schedule for failed LLM calls |