Understand ell model fallback behavior
mainell.config.register_model or pass a client explicitly during the function call.repository·main·Indexed 26 days ago
https://github.com/madcowd/ellA lightweight, functional prompt engineering framework that treats prompts as programs (Language Model Programs) rather than simple strings. ell provides tools for versioning, monitoring, and multimodal interaction with LLMs, including Ell Studio for visualization and prompt version control. It features a provider-agnostic API, caching via registered stores, and support for multi-step conversations through ell.chat.
ell.config.register_model or pass a client explicitly during the function call.To optimize a prompt using few-shot learning, you must explicitly mark the function as learnable. Standard @ell.function or @ell.simple definitions will raise a NotLearnableError if passed directly to an optimizer.
Use ell.learnable() to wrap your function, making it compatible with ell.FewShotOptimizer().fit(learnable, x=x, y=y).
npm run build to create a production-ready build in the build folder. This command bundles React in production mode and optimizes the build for performance. The output is minified and includes file hashes in the filenames, making it ready for deployment.npm run buildFor models that do not natively support Pydantic via response_format (such as gpt-3.5-turbo), you must manually prompt the model to return JSON. You can provide the schema by using MovieReview.model_json_schema() within a system prompt. Since automatic parsing is not yet available for these manual flows, you must use Model.model_validate_json() on the returned string to convert it back into a Pydantic object.
from pydantic import BaseModel, Field
class MovieReview(BaseModel):
title: str = Field(description="The title of the movie")
rating: int = Field(description="The rating of the movie out of 10")
summary: str = Field(description="A brief summary of the movie")
@ell.simple(model="gpt-3.5-turbo")
def generate_movie_review_manual(movie: str):
return [
ell.system(f"""You are a movie review generator. Given the name of a movie, you need to return a structured review in JSON format.
You must absolutely respond in this format with no exceptions.
{MovieReview.model_json_schema()}
"""),
ell.user("Review the movie: {movie}"),
]
# Generate and manually parse
unparsed = generate_movie_review_manual("The Matrix")
parsed = MovieReview.model_validate_json(unparsed)You can pass LLM parameters (like temperature, max_tokens, stop, etc.) to the model in two ways:
@ell.simple decorator.api_params keyword arguments when invoking the decorated function.An evaluation in ell is a structured suite used to measure a Language Model Program's (LMP) performance. It requires three components:
[{"input": {"key": "val"}, "expected_output": "target"}]).(datapoint, output) and return a measurable quantity (e.g., a float).@ell.simple that performs the task.To run the evaluation, instantiate ell.evaluation.Evaluation and call its .run() method, passing the LMP function as the argument.
import ell
ell.init(store="./logdir") # Enable versioning and storage
# 1. Define an LMP:
@ell.simple(model="gpt-4o", max_tokens=10)
def classify_sentiment(text: str):
"""You are a sentiment classifier. Return 'positive' or 'negative'.""
return f"Classify sentiment: {text}"
# 2. A small dataset:
dataset = [
{"input": {"text": "I love this product!"}, "expected_output": "positive"},
{"input": {"text": "This is terrible."}, "expected_output": "negative"}
]
# 3. A metric function that checks correctness:
def accuracy_metric(datapoint, output):
return float(datapoint["expected_output"].lower() in output.lower())
# 4. Constructing the eval:
eval = ell.evaluation.Evaluation(
name="sentiment_eval",
dataset=dataset,
metrics={"accuracy": accuracy_metric}
)
# Run the eval:
result = eval.run(classify_sentiment)
print("Average accuracy:", result.results.metrics["accuracy"].mean())npm start to run the application in development mode. The app will be available at http://localhost:3000. The page will automatically reload when you make changes, and lint errors will appear in the console.npm startUse @ell.simple for straightforward text-in, text-out interactions. It optimizes for readability by returning strings.
Use @ell.complex when you need:
Message objects containing metadata and helper functions.If you want to avoid the default prompt used by ell or require a specific generation logic, you can provide a custom generator function to the @ell.tool decorator. The generator should accept the tool's source code as a string and return a valid JSON tool specification.
Example pattern for a custom generator:
@ell.simple) that takes tool_source: str and returns the schema.@ell.tool(autogenerate=...).@ell.simple
def my_custom_tool_spec_generator(tool_source: str):
# User implements this once in their code base or repo
...
@ell.tool(autogenerate=my_custom_tool_spec_generator)
def search_twitter(query, n=7):
...
@ell.complex(model="gpt-4o", tools=[search_twitter])
def my_llm_program(message_history: List[Message]) -> List[Message]:
...ell-studio project uses standard npm scripts for development, testing, and production builds. Run these commands from the project directory.To enable automatic versioning, serialization of prompts, and local storage of LMP calls, call ell.init() with a specified storage directory. This allows you to treat prompt engineering like machine learning checkpointing, saving the source code and invocation data to a local store.
import ell
ell.init(store='./logdir') # Versions your LMPs and their callsYou can ensure language model responses adhere to a specific schema by passing a Pydantic model to the response_format argument of the @ell.complex decorator. This is currently only supported for the gpt-4o-2024-08-06 model. When using this method, the resulting message object contains a .parsed attribute that holds the instantiated Pydantic model.
from pydantic import BaseModel, Field
class MovieReview(BaseModel):
title: str = Field(description="The title of the movie")
rating: int = Field(description="The rating of the movie out of 10")
summary: str = Field(description="A brief summary of the movie")
@ell.complex(model="gpt-4o-2024-08-06", response_format=MovieReview)
def generate_movie_review(movie: str) -> MovieReview:
"""You are a movie review generator. Given the name of a movie, you need to return a structured review."""
return f"generate a review for the movie {movie}"
# Usage
message = generate_movie_review("The Matrix")
review = message.parsed
print(f"Movie Title: {review.title}")