llm (Simon Willison)
CLI ToolFreeCLI for LLMs — multi-provider, conversation history, templates, embeddings, plugin ecosystem.
Capabilities13 decomposed
provider-agnostic model abstraction with unified interface
Medium confidenceImplements a dual sync/async base class architecture (Model, AsyncModel, KeyModel, AsyncKeyModel) defined in llm/models.py that abstracts away provider-specific implementation details. All models inherit from these base classes and implement a common prompt()/execute() interface, allowing identical code to work across OpenAI, Anthropic, Google, and local models without conditional logic. The plugin system auto-discovers and registers models via entry points, enabling runtime model swapping without code changes.
Uses inheritance-based abstraction with separate sync/async class hierarchies (Model vs AsyncModel) rather than wrapper patterns, enabling native async support without callback hell. Plugin entry points auto-discover models at runtime, eliminating hardcoded provider lists. The Prompt and Response classes encapsulate all input/output concerns (attachments, tools, schema, usage) in reusable objects rather than scattered parameters.
More flexible than LangChain's LLMBase because it supports both sync and async natively without requiring separate implementations, and its plugin system allows third-party models without forking the codebase.
persistent conversation history with sqlite logging
Medium confidenceAutomatically logs all model interactions to a SQLite database (logs.db) with full conversation state preservation. The Conversation class maintains multi-turn dialogue state, and the logging system records prompts, responses, model metadata, tokens used, and timestamps. Conversations can be resumed, queried, and exported. The database schema supports efficient retrieval of conversation history and enables analytics on model usage patterns across sessions.
Uses SQLite as the default persistence layer rather than in-memory or cloud storage, enabling offline-first workflows and full local control. The Conversation class encapsulates multi-turn state as a first-class object with prompt()/responses properties, making conversation management explicit rather than implicit. Logging is automatic and transparent—no explicit save calls required.
Simpler than LangChain's memory abstractions because it uses a single SQLite schema for all conversation types, avoiding the complexity of choosing between ConversationBufferMemory, ConversationSummaryMemory, etc.
response streaming and incremental output handling
Medium confidenceImplements streaming responses using Python iterators, allowing models to return output incrementally as tokens are generated. The Response and AsyncResponse classes provide both streaming (via __iter__) and buffered (via text()) interfaces, enabling developers to choose between real-time output and complete responses. Streaming is transparent to the caller—the same code works with streaming and non-streaming models. The CLI uses streaming by default for responsive user experience.
Uses Python iterators for streaming rather than callbacks or async generators, enabling simple for-loop consumption of streamed output. The Response class provides both streaming (__iter__) and buffered (text()) interfaces, allowing callers to choose their preferred consumption pattern. Streaming is provider-agnostic—the same code works with OpenAI, Anthropic, and other streaming providers.
More Pythonic than callback-based streaming because it uses iterators, which are idiomatic Python. Simpler than managing async generators because streaming works with both sync and async models through the same interface.
model cost tracking and token usage analytics
Medium confidenceAutomatically tracks token usage (input/output tokens) and estimated costs for each model interaction. The Response class includes a usage() method that returns token counts and cost estimates based on model pricing. Usage data is logged to the SQLite database alongside conversation history, enabling analytics on cost per conversation, cost per model, and token efficiency. The system supports custom pricing definitions for models, allowing accurate cost tracking for non-standard pricing models.
Integrates cost tracking into the Response object, making usage and cost data available immediately after model execution without separate API calls. Pricing definitions are pluggable, allowing custom pricing for non-standard models. Cost data is logged to SQLite alongside conversation history, enabling historical analysis and trend tracking.
More integrated than external cost tracking tools because cost data is captured automatically without additional instrumentation. Simpler than building custom cost tracking because pricing definitions are built-in for major providers.
async/await support with native coroutine execution
Medium confidenceProvides full async/await support through AsyncModel and AsyncKeyModel base classes, enabling non-blocking LLM interactions in async applications. All core operations (prompt execution, tool calling, embedding generation) have async equivalents that return coroutines. The system supports both sync and async models in the same application, with automatic detection of execution context. Async responses use AsyncResponse with async iterators for streaming, enabling efficient concurrent LLM calls.
Provides separate AsyncModel and AsyncKeyModel classes rather than mixing async into the base Model class, enabling clear separation of concerns. Async responses use async iterators for streaming, enabling efficient concurrent streaming without blocking. The system supports both sync and async models in the same application, allowing gradual migration to async.
More explicit than LangChain's async support because it uses separate async classes rather than overloading sync methods with async variants. Better for high-concurrency scenarios because async execution is native rather than wrapped in thread pools.
tool execution and function calling with python function registry
Medium confidenceEnables models to call Python functions via a Tool abstraction and Toolbox collection system. Developers decorate Python functions with @llm.tool() to register them, and the system serializes function signatures into schemas that models understand (OpenAI function calling, Anthropic tool_use, etc.). When a model requests tool execution, the framework automatically invokes the Python function, captures the result, and feeds it back to the model in a loop until completion. Tools can be organized into named Toolbox collections for reuse across conversations.
Uses Python decorators (@llm.tool()) for function registration rather than explicit schema definitions, reducing boilerplate. The Toolbox class groups related tools into reusable collections, enabling tool composition. Tool execution is provider-agnostic—the same Python function works with OpenAI function calling, Anthropic tool_use, and other providers without modification.
More Pythonic than LangChain's Tool abstraction because it leverages decorators and type hints for automatic schema generation, and it supports both sync and async execution natively without separate implementations.
schema-based structured output with json validation
Medium confidenceProvides a Schema system that allows developers to define expected output structure (via JSON Schema or Pydantic models) and pass it to models. The framework serializes the schema and sends it to the model provider (e.g., OpenAI's JSON mode, Anthropic's structured output). Model responses are automatically validated against the schema and parsed into structured objects. This enables reliable extraction of specific fields (e.g., name, email, sentiment) from model outputs without regex parsing or post-hoc validation.
Abstracts schema representation away from specific provider formats—the same Schema object works with OpenAI's JSON mode, Anthropic's structured output, and other providers. Validation happens automatically after model execution without explicit post-processing. Supports both JSON Schema and Pydantic models as input, enabling flexibility in schema definition.
More provider-agnostic than using OpenAI's JSON mode directly because it normalizes schema handling across providers. Simpler than LangChain's output parsers because schema validation is built-in rather than requiring separate parser chains.
embedding generation and batch processing with vector storage
Medium confidenceProvides an EmbeddingModel abstraction for generating vector embeddings from text. The system supports both single embed() and batch embed_batch() operations, with embeddings stored in a separate SQLite database (embeddings.db). Embeddings can be used for semantic search, similarity comparisons, and clustering. The framework handles provider-specific embedding APIs (OpenAI, Anthropic, local models) through the same interface, and embeddings are cached to avoid redundant API calls.
Uses a separate SQLite database (embeddings.db) for vector storage rather than mixing with conversation logs, enabling independent scaling and backup strategies. The EmbeddingModel abstraction supports both single and batch operations with automatic caching, reducing redundant API calls. Provider-agnostic interface allows swapping embedding models without code changes.
Simpler than LangChain's embedding abstractions because it provides a single embed() and embed_batch() interface rather than requiring separate Embeddings and AsyncEmbeddings classes. Built-in caching reduces API costs compared to naive embedding approaches.
template system with variable interpolation and prompt reuse
Medium confidenceProvides a template system that allows developers to define reusable prompt templates with variable placeholders. Templates are stored as files or registered via the plugin system, and variables are interpolated at runtime using Jinja2-style syntax. This enables prompt engineering best practices like prompt versioning, A/B testing, and separation of prompt logic from application code. Templates can include system prompts, examples, and tool definitions, making complex prompts composable and maintainable.
Integrates templates into the plugin system, allowing templates to be distributed and discovered like models and tools. Templates are first-class objects with metadata (name, description, variables), enabling template discovery and documentation. Jinja2 syntax provides powerful variable interpolation without requiring custom template languages.
More integrated than external prompt management tools because templates are part of the llm ecosystem and work seamlessly with the CLI and Python API. Simpler than LangChain's PromptTemplate because it uses standard Jinja2 syntax rather than custom placeholder syntax.
multi-modal input handling with attachments and fragments
Medium confidenceSupports attaching images, audio, files, and other media to prompts via the Prompt class. Attachments are represented as Fragment objects that encapsulate file paths, MIME types, and metadata. The system handles encoding attachments into formats that models understand (base64 for images, file references for documents). Multi-modal models (e.g., GPT-4 Vision, Claude 3 Vision) automatically receive attachments in their native format without requiring manual encoding.
Uses Fragment objects to encapsulate attachment metadata (MIME type, encoding, path) rather than passing raw file paths, enabling provider-specific encoding strategies. Attachments are part of the Prompt class, making multi-modal input a first-class concern rather than an afterthought. Automatic encoding handles base64 conversion and format negotiation with models.
More integrated than manually encoding images to base64 because the framework handles encoding and format negotiation automatically. Supports more attachment types than some LLM libraries because it abstracts attachment handling through the Fragment system.
plugin system with entry point discovery and dynamic model registration
Medium confidenceImplements a plugin architecture using Python entry points for dynamic discovery and registration of models, tools, and templates. Plugins are Python packages that define entry points in their setup.py/pyproject.toml, and the llm package auto-discovers them at runtime without requiring code changes. Plugins can add new models (e.g., local Ollama models, custom fine-tuned models), tools, templates, and commands. The plugin system is extensible—developers can create plugins without modifying the core llm codebase.
Uses Python entry points for plugin discovery rather than hardcoded imports or configuration files, enabling zero-configuration plugin installation. Plugins are first-class citizens—models, tools, and templates added via plugins are indistinguishable from built-in ones. The plugin system supports both sync and async models, tools, and commands without requiring separate plugin types.
More Pythonic than LangChain's integration approach because it uses standard Python packaging and entry points rather than custom plugin loaders. Simpler to distribute plugins because they're just Python packages installable via pip.
cli with streaming output and interactive chat mode
Medium confidenceProvides a command-line interface (llm command) that supports both one-shot prompts and interactive multi-turn chat. The CLI streams model responses in real-time using iterators, enabling responsive user experience without waiting for full response completion. Interactive mode maintains conversation state across turns, with readline support for command history and editing. The CLI integrates with all core features (tools, templates, schemas, embeddings) and supports piping input/output for shell integration.
Uses Python iterators for streaming responses, enabling real-time output without buffering entire responses. Interactive mode is built on the Conversation class, reusing the same persistence and state management as the Python API. CLI commands map directly to Python API functions, ensuring feature parity between CLI and programmatic access.
More responsive than non-streaming CLIs because it displays output as it arrives rather than waiting for completion. Better shell integration than web-based LLM interfaces because it supports piping and works in headless environments.
configuration management with api keys and model aliases
Medium confidenceManages API keys, model aliases, and user preferences through configuration files (typically ~/.llm/config.yaml or environment variables). The system supports multiple API key sources (environment variables, config files, keychain) with a priority order. Model aliases allow users to define shortcuts (e.g., 'gpt4' -> 'gpt-4-turbo') and set default models. Configuration is loaded at startup and can be modified via CLI commands (llm keys set, llm aliases set) without manual file editing.
Supports multiple API key sources with explicit priority order (environment variables > config file > keychain), enabling flexible deployment scenarios. Model aliases are first-class configuration, allowing users to define shortcuts without code changes. Configuration is loaded once at startup and cached, avoiding repeated file I/O.
More flexible than hardcoding API keys because it supports environment variables, config files, and keychain storage. Simpler than external secrets management tools because configuration is built-in and requires no additional setup.
Capabilities are decomposed by AI analysis. Each maps to specific user intents and improves with match feedback.
Related Artifactssharing capabilities
Artifacts that share capabilities with llm (Simon Willison), ranked by overlap. Discovered automatically through the match graph.
5ire
5ire is a cross-platform desktop AI assistant, MCP client. It compatible with major service providers, supports local knowledge base and tools via model context protocol servers .
5ire
5ire is a cross-platform desktop AI assistant, MCP client. It compatible with major service providers, supports local knowledge base and tools via model context protocol servers .
chatbox
Powerful AI Client
aidea
An APP that integrates mainstream large language models and image generation models, built with Flutter, with fully open-source code.
Local GPT
Chat with documents without compromising privacy
Mods
Pipe CLI output through AI models.
Best For
- ✓developers building multi-provider LLM applications
- ✓teams evaluating different model providers
- ✓tool builders who want provider independence
- ✓developers building interactive LLM applications requiring session persistence
- ✓teams needing audit trails for LLM interactions
- ✓researchers analyzing model behavior across multiple conversations
- ✓developers building interactive LLM applications with real-time feedback
- ✓teams needing responsive user experiences with large model outputs
Known Limitations
- ⚠Async/sync duality requires understanding of both execution models; mixing them requires careful context management
- ⚠Provider-specific features (e.g., vision models, function calling variants) must be normalized to common interface, potentially losing nuanced capabilities
- ⚠Plugin discovery relies on Python entry points; requires proper package installation for models to be discoverable
- ⚠SQLite is single-writer; high-concurrency scenarios require external database migration
- ⚠Conversation state is stored locally; no built-in cloud sync or multi-device access
- ⚠Large conversation histories (10k+ turns) may experience query slowdown without proper indexing
Requirements
Input / Output
UnfragileRank
UnfragileRank is computed from adoption signals, documentation quality, ecosystem connectivity, match graph feedback, and freshness. No artifact can pay for a higher rank.
About
CLI tool and Python library for interacting with LLMs. Supports OpenAI, Anthropic, local models via plugins. Features conversation history, templates, embeddings, and a plugin ecosystem. By the creator of Datasette.
Categories
Alternatives to llm (Simon Willison)
Are you the builder of llm (Simon Willison)?
Claim this artifact to get a verified badge, access match analytics, see which intents users search for, and manage your listing.
Get the weekly brief
New tools, rising stars, and what's actually worth your time. No spam.
Data Sources
Looking for something else?
Search →