Search by Meaning, Not by Words
The help centre's search box is why people open support tickets: I accidentally binned an important page, can I get it back? finds nothing, because the article that answers says deleted notes stay in the Trash for 30 days and can be restored. keyword_search (provided) is that box. Replace it with search by meaning.
embedder.embed(texts) is a real embedding model: it turns texts into vectors placed so that texts which mean similar things are close together, whatever words they use. Give it a list of strings and it returns a vector for each, in order; give it one string and it returns one vector. cosine(a, b) says how close two vectors are.
Implement two functions.
build_index(docs) takes the articles, each {"id": ..., "text": ...}, and returns an index: whatever structure you like that keeps each article's id with its vector. Embed all the articles in one call.
search(index, query, k=3) returns the ids of the k articles nearest the query, nearest first. It embeds the query, in one call, and must not embed the articles again: articles change rarely and queries arrive constantly, so the corpus is embedded once and a search costs one small call. Ties go to the smaller id.
The tests count calls and texts embedded, then ask eight questions phrased the way people phrase them: the right article must come first for at least six, and you must beat the keyword search you replaced.