ProfSpeak

2026-10-30

In the age of GenAI, text based communication can often be cumbersome. Many AI models generate verbose texts by default and editing them down for length or clarity is often not done. I have found reading such texts very taxing, even if the content itself is interesting. Then it occurred to me from my academia days how some professors are good at getting to the essence of what needs to be written, with very few words. Maybe we could get AI to write similar to that.

In order to see how this could be done I have set up a small experiment: use a small local model to translate any piece of text into something a professor would write. This ProfSpeak experiment is the topic of this article.

A robot professor translating verbose language into short summaries.

To implement ProfSpeak, we are going to use the ReqLLM framework. ReqLLM itself is a framework in Elixir that abstracts away the implementation details of LLM providers and models and gives a clean and generic API to use them. There are of course libraries in many other languages that can do similar setups.

Getting ReqLLm up and running can be done with very few lines in a fresh Elixir project, where we defined the module ProfSpeak seen below:

defmodule Profspeak do
  @moduledoc """
  Documentation for `Profspeak`.
  """

  @doc """
  translate.

  ## Examples

      iex> Profspeak.translate("Could you perhaps take another look.")
  """
  def model do
    ReqLLM.model!(%{provider: :ollama, id: "granite4:3b"})
  end

  def prompt do
    """
    Rewrite the user's text in concise, direct language.

    First remove unnecessary niceties, politeness, hedging, repetition, and filler.
    Then make only the minimum wording changes needed for clarity.

    Preserve everything else exactly: meaning, intent, timing, urgency,
    conditions, uncertainty, and vague references.

    Do not add information or make the request stronger or weaker.
    Do not explain or interpret the text.

    Return only the rewritten text.
    """
  end

  def translate(text) do
    ReqLLM.generate_text!(model(), text, system_prompt: prompt())
  end
end

The code is reasonably straightforward with the function model setting up the Granite micro (3b) parameters model with our provider Ollama. While many other models could do the job I have found this model very capable for the task while being very small and fast to use. The function translate is doing the actual work of generating text based on a given text, that also uses a system prompt that is also sent to a model. One can see it as a set of instructions to get the model translate the text in a way we intend.

There were a number of variations of the systems prompt and models that were tried before settling on this combination. One of the issues that occurred sometimes is that mentioning professor in the base prompt would make the model rewrite the text more than we aim for. In order to hone in on a useful combination of the right model and prompt a set of tests were run and verified manually.

The following tests were run with the Granite model mentioned above:

---
INPUT:  Would you mind sending me the report when you get a chance? Thanks so much!
OUTPUT: Please send the report as soon as possible.

---
INPUT:  I was just wondering if perhaps you might be able to take a look at this at some point when you have a little bit of time.
OUTPUT: Please review this when you're free.

---
INPUT:  I would greatly appreciate it if you could possibly provide me with your feedback on the attached document at your earliest convenience.
OUTPUT: Please review and provide feedback on the attached document.

---
INPUT:  I think we should probably reconsider this approach, because I'm not entirely sure that this approach is really the best approach for what we're trying to achieve.
OUTPUT: We should rethink this approach since it may not be the most effective way to reach our goals.

---
INPUT:  Would you please send the final version of the report to Sarah before Friday, if that's possible?
OUTPUT: Please send Sarah the final report by Friday.

---
INPUT:  I was wondering if you could take another look at this.
OUTPUT: Please review it again.

Although in the first test the model did change the level of urgency in the output overall the Granite model did a rock solid job (pun intended) at our small test. With very few lines of code and a small local model, we got a result that is pretty in line with what we intended to do.

Of course this was just a very small experiment, but it shows how you can use a small local model to do some interesting things with summarization. One important takeaway for me is, even in such a small experiment, repeatedly testing the right input and model combination is a necessity when it comes to GenAI use. Ideally we would also immediately setup a test suite that can run the various combinations of models and prompts, and ideally even evaluate them. Exploring such testing is probably a worthwhile endeavor for another article.