AIHelpMe.ALLOWED_PACKS
— ConstantALLOWED PACKS
Currently available packs are:
:julia
- Julia documentation, standard library docstrings and a few extras (for Julia v1.10):juliadata
- JuliaData.jl organization documentation, eg, DataFrames.jl and similar packages:genie
- GenieFramework organization documentation, eg, Genie.jl, Stipple.jl, StippleUI.jl, etc:plots
- Plots.jl organization documentation, eg, Plots.jl, StatsPlots.jl, etc:makie
- Makie.jl organization documentation:tidier
- Tidier.jl organization documentation:sciml
- SciML organization documentation
These packs have been sourced and packaged with DocsScraper.jl.
AIHelpMe.ALLOWED_PREFERENCES
— ConstantKeys that are allowed to be set via set_preferences!
AIHelpMe.LOADED_PACKS
— ConstantLOADED_PACKS
The knowledge packs that are currently loaded in the index.
AIHelpMe.PREFERENCES
— ConstantPREFERENCES
You can set preferences for AIHelpMe by using the set_preferences!
. It will create a LocalPreferences.toml
file in your current directory and will reload your prefences from there.
Check your preferences by calling get_preferences(key::String)
.
Available Preferences (for set_preferences!
)
MODEL_CHAT
: The default model to use for aigenerate and most ai* calls. SeePromptingTools.MODEL_REGISTRY
for a list of available models or define your own withPromptingTools.register_model!
.MODEL_EMBEDDING
: The default model to use for aiembed (embedding documents). SeePromptingTools.MODEL_REGISTRY
for a list of available models or define your own withPromptingTools.register_model!
.EMBEDDING_DIMENSION
: The dimension of the embedding vector. Defaults to 1024 (truncated OpenAI embedding). Set to 0 to use the maximum allowed dimension.LOADED_PACKS
: The knowledge packs that are loaded on restart/refresh (load_index!()
).
AIHelpMe.RAG_CONFIGURATIONS
— ConstantRAG_CONFIGURATIONS
A dictionary of RAG configurations, keyed by a unique symbol (eg, bronze
). Each entry contains a dictionary with keys :config
and :kwargs
, where :config
is the RAG configuration object (AbstractRAGConfig
) and :kwargs
the NamedTuple of corresponding kwargs.
Available Options:
:bronze
: A simple configuration for a bronze pipeline, using truncated binary embeddings (dimensionality: 1024) and no re-ranking or refinement.:silver
: A simple configuration for a bronze pipeline, using truncated binary embeddings (dimensionality: 1024) but also enables re-ranking step.:gold
: A more complex configuration, similar to:simpler
, but using a standard embeddings (dimensionality: 3072, type: Float32). It also leverages re-ranking and refinement with a web-search.
AIHelpMe.aihelp
— Methodaihelp([cfg::RT.AbstractRAGConfig, index::RT.AbstractChunkIndex,]
question::AbstractString;
verbose::Integer = 1,
model = MODEL_CHAT,
return_all::Bool = false)
Generates a response for a given question using a Retrieval-Augmented Generation (RAG) approach over Julia documentation (or any other knowledge pack).
If you return RAGResult (return_all=true
), you can use AIHelpMe.pprint
to pretty-print the result and see the sources/"support" scores for each chunk of the answer.
The answer will depend on the knowledge packs loaded, see ?load_index!
.
You can also use add docstrings from any package you have loaded (or all of them), see ?update_index
and make sure to provide your new updated index explicitly!
Arguments
cfg::AbstractRAGConfig
: The RAG configuration.index::AbstractChunkIndex
: The chunk index (contains chunked and embedded documentation).question::AbstractString
: The question to be answered.model::String
: A chat/generation model used for generating the final response, default isMODEL_CHAT
.return_all::Bool
: Iftrue
, returns aRAGResult
(provides details of the pipeline + allows pretty-printing withpprint(result)
).search::Union{Nothing, Bool}
: Iftrue
, uses TavilySearchRefiner to add web search results to the context. See?PromptingTools.Experimental.RAGTools.TavilySearchRefiner
for details.rerank::Union{Nothing, Bool}
: Iftrue
, uses CohereReranker to rerank the chunks. See?PromptingTools.Experimental.RAGTools.CohereReranker
for details.
Returns
- If
return_all
isfalse
, returns the generated message (msg
). - If
return_all
istrue
, returns aRAGResult
(provides details of the pipeline + allows pretty-printing withpprint(result)
)
Notes
- Function always saves the last context in global
LAST_RESULT
for inspection of sources/context regardless ofreturn_all
value.
Examples
Using aihelp
to get a response for a question:
using AIHelpMe: build_index
index = build_index(...) # create an index that contains Makie.jl documentation (or any loaded package that you have)
question = "How to make a barplot in Makie.jl?"
msg = aihelp(index, question)
If you want a pretty-printed answer with highlighted sources, you can use the return_all
argument and pprint
utility:
using AIHelpMe: pprint
result = aihelp(index, question; return_all = true)
pprint(result)
If you loaded a knowledge pack, you do not have to provide the index.
# Load Makie knowledge pack
AIHelpMe.load_index!(:makie)
question = "How to make a barplot in Makie.jl?"
msg = aihelp(question)
If you know it's a hard question, you can use the search
and rerank
arguments to add web search results to the context and rerank the chunks.
using AIHelpMe: pprint
question = "How to make a barplot in Makie.jl?"
result = aihelp(question; search = true, rerank = true, return_all = true)
pprint(result) # nicer display with sources for each chunk/sentences (look for square brackets)
AIHelpMe.docdata_to_source
— Methoddocdata_to_source(data::AbstractDict)
Creates a source path from a given DocStr record
AIHelpMe.docextract
— Functiondocextract(d::DocStr, sep::AbstractString = "
")
Extracts the documentation from a DocStr record. Separates the individual docs within DocStr
with sep
.
AIHelpMe.docextract
— Functiondocextract(modules::Vector{Module} = Base.Docs.modules)
Extracts the documentation from a vector of modules
.
AIHelpMe.docextract
— Functiondocextract(d::MultiDoc, sep::AbstractString = "
")
Extracts the documentation from a MultiDoc record (separates the individual docs within DocStr
with sep
)
AIHelpMe.docextract
— Methoddocextract(mod::Module)
Extracts the documentation from a given (loaded) module.
AIHelpMe.find_new_chunks
— Methodfind_new_chunks(old_chunks::AbstractVector{<:AbstractString},
new_chunks::AbstractVector{<:AbstractString})
Identifies the new chunks in new_chunks
that are not present in old_chunks
.
Returns a mask of chunks that are new (not present in old_chunks
).
Uses SHA256 hashes to dedupe the strings quickly and effectively.
AIHelpMe.get_config_key
— FunctionReturns the configuration key for the given cfg
and kwargs
to use the relevant artifacts.
AIHelpMe.get_preferences
— Methodget_preferences(key::String)
Get preferences for AIHelpMe. See ?PREFERENCES
for more information.
See also: set_preferences!
Example
AIHelpMe.get_preferences("MODEL_CHAT")
AIHelpMe.last_result
— Methodlast_result()
Returns the RAGResult from the last aihelp
call. It can be useful to see the sources/references used by the AI model to generate the response.
If you're using aihelp()
make sure to set return_all = true
to return the RAGResult.
AIHelpMe.load_index!
— Functionload_index!(packs::Vector{Symbol}=LOADED_PACKS; verbose::Bool = true, kwargs...)
load_index!(pack::Symbol; verbose::Bool = true, kwargs...)
Loads one or more packs
into the main index from our pre-built artifacts.
Availability of packs might vary depending on your pipeline configuration (ie, whether we have the correct embeddings for it). See AIHelpMe.ALLOWED_PACKS
Example
load_index!(:julia)
Or multiple packs
load_index!([:julia, :juliadata, :makie, :tidier, :plots, :sciml, :genie])
But we recommend loading ONLY the packs you expect to need - unnecessary packs introduce noise.
AIHelpMe.load_index!
— Methodload_index!(file_path::AbstractString;
verbose::Bool = true, kwargs...)
Loads the serialized index in file_path
into the global variable MAIN_INDEX
.
Supports .jls
(serialized Julia object) and .hdf5
(HDF5.jl) files.
AIHelpMe.load_index!
— Methodload_index!(index::RT.AbstractChunkIndex;
verbose::Bool = 1, kwargs...)
Loads the provided index
into the global variable MAIN_INDEX
.
If you don't have an index
yet, use build_index
to build one from your currently loaded packages (see ?build_index
)
Example
# build an index from some modules, keep empty to embed all loaded modules (eg, `build_index()`)
index = AIH.build_index([DataFramesMeta, DataFrames, CSV])
AIH.load_index!(index)
AIHelpMe.load_index_hdf5
— MethodHacky function to load a HDF5 file into a ChunkIndex object. Only bare-bone ChunkIndex is supported right now.
AIHelpMe.set_preferences!
— Methodset_preferences!(pairs::Pair{String, <:Any}...)
Set preferences for AIHelpMe. See ?PREFERENCES
for more information.
See also: get_preferences
Example
Change your API key and default model:
# EMBEDDING_DIMENSION of 0 means the maximum allowed
AIHelpMe.set_preferences!("MODEL_CHAT" => "llama3", "MODEL_EMBEDDING" => "nomic-embed-text", "EMBEDDING_DIMENSION" => 0)
AIHelpMe.update_index
— Functionupdate_index(index::RT.AbstractChunkIndex = MAIN_INDEX,
modules::Vector{Module} = Base.Docs.modules;
verbose::Integer = 1,
kwargs...)
Updates the provided index
with the documentation of the provided modules
.
Deduplicates against the index.sources
and embeds only the new document chunks (as measured by a hash).
Returns the updated index
(new instance).
For available configurations and customizations, see the corresponding modules and functions of PromptingTools.Experimental.RAGTools
(eg, build_index
).
Example
If you loaded some new packages and want to add them to your MAIN_INDEX (or any index
you use), run:
# To update the MAIN_INDEX as well
AIHelpMe.update_index() |> AHM.load_index!
# To update an explicit index
index = AIHelpMe.update_index(index)
AIHelpMe.update_pipeline!
— Functionupdate_pipeline!(option::Symbol = :bronze; model_chat = MODEL_CHAT,
model_embedding = MODEL_EMBEDDING, verbose::Bool = true, embedding_dimension::Integer = EMBEDDING_DIMENSION)
Updates the default RAG pipeline to one of the pre-configuration options and sets the requested chat and embedding models.
This is a good way to update model types to change between OpenAI models and Ollama models.
See available pipeline options via keys(RAG_CONFIGURATIONS)
.
Logic:
- Updates the global
MODEL_CHAT
andMODEL_EMBEDDING
to the requested models. - Updates the global
EMBEDDING_DIMENSION
for the requested embedding dimensionality after truncation (embedding_dimension
). - Updates the global
RAG_CONFIG
andRAG_KWARGS
to the requestedoption
. - Updates the global
LOADED_CONFIG_KEY
to the configuration key for the givenoption
andkwargs
(used by the artifact system to download the correct knowledge packs).
Example
update_pipeline!(:bronze; model_chat = "gpt4t")
You don't need to re-load your index if you just change the chat model.
You can switch the pipeline to Ollama models: Note: only 1 Ollama embedding model is supported for embeddings now! You must select "nomic-embed-text" and if you do, set embedding_dimension=0
(maximum dimension available)
update_pipeline!(:bronze; model_chat = "llama3", model_embedding="nomic-embed-text", embedding_dimension=0)
# You must download the corresponding knowledge packs via `load_index!` (because you changed the embedding model)
load_index!()
PromptingTools.Experimental.RAGTools.build_index
— FunctionRT.build_index(modules::Vector{Module} = Base.Docs.modules; verbose::Int = 1,
kwargs...)
Build index from the documentation of the currently loaded modules. If modules
is empty, it will use all currently loaded modules.
PromptingTools.Experimental.RAGTools.build_index
— MethodRT.build_index(mod::Module; verbose::Int = 1, kwargs...)
Build index
from the documentation of a given module mod
.
AIHelpMe.@aihelp!_str
— Macroaihelp!"user_question"[model_alias] -> AIMessage
The aihelp!""
string macro is used to continue a previous conversation with the AI model.
It appends the new user prompt to the last conversation in the tracked history (in AIHelpMe.CONV_HISTORY
) and generates a response based on the entire conversation context. If you want to see the previous conversation, you can access it via AIHelpMe.CONV_HISTORY
, which keeps at most last PromptingTools.MAX_HISTORY_LENGTH
conversations.
It does NOT provide new context from the documentation. To do that, start a new conversation with aihelp"<question>"
.
Arguments
user_question
(String): The follow up question to be added to the existing conversation.model_alias
(optional, any): Specify the model alias of the AI model to be used (seePT.MODEL_ALIASES
). If not provided, the default model is used.
Returns
AIMessage
corresponding to the new user prompt, considering the entire conversation history.
Example
To continue a conversation:
# start conversation as normal
aihelp"How to create a dictionary?"
# ... wait for reply and then react to it:
# continue the conversation (notice that you can change the model, eg, to more powerful one for better answer)
aihelp!"Can you create it from named tuple?"gpt4t
# AIMessage("Yes, you can create a dictionary from a named tuple ...")
Usage Notes
- This macro should be used when you want to maintain the context of an ongoing conversation (ie, the last
ai""
message). - It automatically accesses and updates the global conversation history.
- If no conversation history is found, it raises an assertion error, suggesting to initiate a new conversation using
ai""
instead.
Important
Ensure that the conversation history is not too long to maintain relevancy and coherence in the AI's responses. The history length is managed by MAX_HISTORY_LENGTH
.
AIHelpMe.@aihelp_str
— Macroaihelp"user_question"[model_alias] -> AIMessage
The aihelp""
string macro generates an AI response to a given user question by using aihelp
under the hood. It will automatically try to provide the most relevant bits of the documentation (from the index) to the LLM to answer the question.
See also aihelp!""
if you want to reply to the provided message / continue the conversation.
Arguments
user_question
(String): The question to be answered by the AI model.model_alias
(optional, any): Provide model alias of the AI model (seeMODEL_ALIASES
).
Returns
AIMessage
corresponding to the input prompt.
Example
result = aihelp"Hello, how are you?"
# AIMessage("Hello! I'm an AI assistant, so I don't have feelings, but I'm here to help you. How can I assist you today?")
If you want to interpolate some variables or additional context, simply use string interpolation:
a=1
result = aihelp"What is `$a+$a`?"
# AIMessage("The sum of `1+1` is `2`.")
If you want to use a different model, eg, GPT-3.5 Turbo, you can provide its alias as a flag:
result = aihelp"What is `1.23 * 100 + 1`?"gpt3t
# AIMessage("The answer is 124.")