25 · Feedback and the learned vocabulary¶
The router reads a turn by the words your tools declare. Your users have words of their own -- take order
4411 off the card where your tool says refund_card -- and their thumbs teach the router those words. This
chapter is what a thumb records, how the hosted miner turns thumbs into a new vocabulary, and how a
vocabulary is reverted.
Language support
The selector reads turns written in English and in Brazilian Portuguese (pt-BR). The language is chosen, never guessed from the turn: the console's Settings page (Language the selector reads), language on a plan request, or the settings.language of your vocabulary file; with none of them, English. A Portuguese turn may be typed with its accents or without them. European Portuguese is not a grammar the selector has, and a turn in any other language is unread.
A thumb¶
A person's thumb, up or down, on what the router chose is one feedback record. In a session:
with Client() as client:
chat = client.session("desk", catalogue=catalogue, rulebook=rulebook)
plan = chat.read("show me order 4411")
print(chat.thumbs(plan, up=True)) # the router chose well
plan = chat.read("take order 4411 off the card")
print(plan.steps[0].selection.tool, "->", chat.thumbs(plan, up=False, corrected="refund_card"))
The second turn reached get_order, and the thumb down says the tool meant was refund_card (corrected).
A retry of the same thumb is one record on the service. An agent of Part I does the same with
agent.thumbs(reply, up=...), and LangChain's callback with StalwartFeedbackCallback (chapter
27).
A thumb down is worth most with what was meant. agent.meant_choices(reply) -- meant_choices(rated) beside
LangChain's callback -- lists what to offer the person: the
tools the router weighed first -- the ones it asked between, or both readings of a word it read two ways --
then every other tool the agent could reach, and "" last for "none of these". Their answer is corrected.
What a record holds¶
desk = Agent.from_file("agent.yaml")
reply = desk.chat("show me order 4411", user="u-17")
print(json.dumps(desk.feedback_record(reply, up=True), indent=1, sort_keys=True))
{'accepted': 1}
get_order -> {'accepted': 1}
{
"agent": "desk",
"cited": [],
"context": {
"before": [],
"history": "first",
"previous": [],
"readings": [],
"step": 0,
"steps": 1
},
"corrected": "",
"decided_by": "tool: admission",
"delegated": false,
"outcomes": [
"get_order:done"
],
"reply_digest": "1bfd98bf2f6401b4e33432e2778566c3d8b4d5a315f0b10ca25d1706a6a2d733",
"rewrites": [],
"router_digest": "",
"thumb": "up",
"tool": "get_order",
"turn": "show me order 4411",
"verdict": "resolved",
"visible": [
"charge_card",
"get_order",
"hand_off",
"read_inbox",
"send_receipt"
],
"vocabulary_digest": "2430f1a2ad2982d0067885488a4c89e21ad1d7c83b115ba8f1b20acc88dfaea8"
}
ThumbRefused: personal data in the request, so nothing was sent: a telephone number at turn. Remove it, or put a placeholder in its place (an address at example.com, say), and send the request again
The record is the rated turn's words with the router's reading of them: the turn, the agent, the tools it
could see (visible), the tool it chose and the rule that chose it (decided_by), the outcome (verdict),
the vocabulary it read with, and the thumb. What the reply said is held only as what was done -- each
action's outcome (outcomes) and the passages it cited -- and a digest of its text: never the reply's
words, an argument's value, a tool's result or an earlier turn.
A record also holds the context the turn was read in (context), because the router reads by context
and is right or wrong only in it: tag lists please asks for the tag lists where your tools only list them,
and tags lists where a tool tags them. The context is the rated step's place in its plan (step, steps) and
the tools of the steps before it (before), what the turn before did -- first, asked, answered or
declined (history) -- and the tools it called or asked between (previous), and, where the router read a
word two ways, the tools both readings reached (readings). Tool names only: no earlier turn's words.
The miner learns from the turn's words, so the record is screened for personal data on your machine before it is sent, and a thumb on a turn that holds some is refused, with nothing sent:
reply = desk.chat("show me order 4411, my number is 07700 900123", user="u-17")
try:
desk.thumbs(reply, up=True)
except ThumbRefused as refused:
print("ThumbRefused:", refused)
The output's last line. A thumb on a whole turn of several instructions, on an answer the conversation decided, or on the reply after a confirmation is refused too, naming what to thumb instead: these are not readings of the person's words.
Records are kept under your plan's retention (chapter 16), read by nobody else, and
never used for training. GET /v1/feedback/summary counts the last thirty days' thumbs by what they were on
-- a tool the router chose, a turn the model took, a question the router asked, an answer from your sources
-- and GET /v1/feedback/export gives every stored record as a line of JSON, which is what a team that runs
its own miner reads.
The hosted miner¶
POST /v1/vocabulary/mine (or client.mine(model)) queues a learning run over your stored feedback and your
live vocabulary, in one language (below). It proposes words your users used for your tools, and applies them only when every one of
its five gates holds and the live vocabulary is still the version it mined over. The gates: no write is
reached wrongly, on your evaluation corpus or on any feedback case; the feedback held back from learning is
answered no worse than before; your corpus's baseline and your dialogues' baselines, where you keep them,
still hold; and the new file checks clean. Its run is answered at once with an id; GET
/v1/vocabulary/mine/{run_id} (client.ledger(run_id)) reads its state -- queued, running, finished,
failed or cancelled -- whether it applied, the version it made live, or the gate that held it back. Its
ledger names each case by digest, never by its words. DELETE /v1/vocabulary/mine/{run_id} withdraws a
queued run; one already running finishes.
The console's Miner page shows the same runs, and its Vocabulary page each version and what its ledger says
(GET /v1/vocabulary/history).
A vocabulary, versioned¶
The live vocabulary (GET /v1/vocabulary, client.vocabulary()) is a file of your words and the tools
they mean. A version stays when the next is made live, so POST /v1/vocabulary/revert -- or
client.revert_vocabulary(), or the Vocabulary page -- makes the one before it live again, one version per
call. PUT /v1/vocabulary publishes a version you wrote yourself. Every plan names the vocabulary it read
with (vocabulary_digest), so a plan that changed can be traced to the version that changed it.
One version is live for each language the router reads: a file is for the language its settings.language
names -- en or pt-BR -- and for English where it names none. GET /v1/vocabulary and POST
/v1/vocabulary/revert take ?language= -- else your Settings page's language -- a feedback record carries
the language its turn was read in, and a learning run mines one language -- the language its body names,
else your Settings page's -- into that language's file alone. A Portuguese thumb never teaches the English
file a word.
The runtime on your machine takes the live version with its next lease refresh, so a version made live, or reverted, reaches your agents within that time.
A sentence shape the router could not read at all -- not a word, but how the sentence is built -- is kept
by a mine run as its shape only, in the router's own alphabet and never a word of yours. GET
/v1/grammar-reports/shipped lists the shapes of yours that a release of the router now reads. A shape goes with
its context's shape, never the context: what the turn before did, where the step stood in its plan, how many
tools a word read two ways reached, and each tool before it as its name's word classes (ACTION OBJECT), never
its name. A shape is kept only where five distinct turns share it in one context. Sending one
yourself is opt-in: a report not consented to is refused (grammar_report_not_consented), and so is one in
an alphabet no release shipped (grammar_report_alphabet_unknown).
The limits¶
Chapter 20's limits hold here, and these besides:
- A vocabulary teaches the router words, not judgement: a word applied for one tool reads that tool wherever it is said.
- The miner applies only what its gates hold, and the gates read the cases you have. A word nobody has thumbed is not learned.