FunctAI.jl
Typed Julia functions whose body a language model writes.
You write the signature; a model writes the body. Then you run it over a column, measure how often it is right, have people rate its calls, improve it, and save it.
using FunctAI
@enum Mood happy unhappy mixed
@ai function mood(review::String)::Mood
"How does the customer feel about what they bought?"
end
mood("It broke after one day.") # unhappy::Mood
df.mood = mood.(df.review) # the whole column, 8 calls at a time
evaluate(mood, labelled) # how often it is right, with a 95% intervalAn AI function is a Julia Function: call it, broadcast it, pass it to ByRow, map it, put it in a @formula. Its answers are the types you declare (an @enum, a struct, Union{Int,Missing}, a Vector), and a reply that doesn't fit its type is asked again, never made up.
What it covers
- Write an AI function with
@ai, or as data withAIFunction; see exactly what the model reads withFunctAI.prompt. - Run it on tables: broadcasting,
mapand DataFrames'ByRowrun the calls concurrently;missingin,missingout. - Measure with
evaluate: a score with a 95% interval, every row as a table;comparetwo versions row by row. - Improve with
labeled_few_shot,bootstrap_few_shot,random_search,instruction_searchandgepa(the instruction rewritten from the function's mistakes); each returns an improved copy. - Model with
AIModel:fit/predictwith formulas, and an MLJ model. - Watch a call with
stream; give it tools (Julia functions); group calls into a@program. - Log every call,
ratethem, and turn ratings into rows with known answers withrated. - Save with
FunctAI.saveand load withFunctAI.load, in any FunctAI language. - Converse: a
conversationis a program's calls that remember each other, kept in a store any process (and Python) opens: branches, helpers that remember only when told, turns stopped or resumed from anywhere. - Ask first: tools say what they do (
effects), andapproveasks a function at once, or a person later, from any process; a turn that waited goes on paying for nothing twice. - Extend with
Plugins: hooks over turns, context, calls, requests and tools, whose changes are recorded;compactionanddelegateare built with them. - Serve a program over HTTP with
serve, and use one served in any language withremote. - Run long: the reply cache (in memory, or on disk, shared with Python), a progress line,
prune_calls,quotes_found, escalation to a model that is surer. - Bake:
FunctAI.bake_exampleswrites the training examples every trainer reads;FunctAI.bakedcalls a student trained anywhere.
One contract, four languages
FunctAI exists in Python, TypeScript, R and Julia, held together by one contract: the same function has the same version, writes the same call log and saves to the same folder in every language. A function improved in Python loads here and sends the same bytes; ratings made in R pool with calls made in Julia.
It stands on two libraries: lmcc (how values are written into a prompt and read back) and lm15 (every provider, one wire, and sign-ins).
Install
Julia 1.10 or later. FunctAI and the two packages under it are not in the General registry yet; add them in this order:
using Pkg
Pkg.add(url = "https://github.com/MaximeRivest/lmcc", subdir = "julia")
Pkg.add(url = "https://github.com/lm15-dev/LM15.jl")
Pkg.add(url = "https://github.com/MaximeRivest/functai", subdir = "julia")Set the key of the provider you use (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, …) in the environment, or sign in once with FunctAI.login. With no model named, FunctAI uses the first provider it finds a key for.
Where to go
- New here: the tutorials, from a first function to decisions, MLJ and living with a function in use.
- A task in mind: the guides.
- Coming from Python or R: where Julia differs.
- A name: the reference, or
?namein the REPL.