A rubbs
BBS::AImodulja (forrás:lib/bbs/ai.rb, 0.5.0 óta) olyan karaktereket ad, akikkel a hívó beszélgethet: hogy ki a karakter, az egy YAML-fájlban (a personában) van, a beszédet egy kis modell végzi bármilyen OpenAI-kompatibilis chat-végpont mögött, hívónként rövid memória tartja a beszélgetést, és beégetett válaszok ugranak be, ha a modell nem elérhető vagy elhasal. Ez az oldal sorra veszi az összes osztályt és kulcsot, megmutatja, hogyan kerül egy karakter doorba vagy window-ba, és hogy éles boardjaink hogyan bánnak a kis modellel. Minden példát a rubbs 0.17.0-n futtattunk, offline vagy egy helyi csonk ellen, valódi modell nélkül. Az API az 1.0.0-ban is ugyanez; a 0.33.0 óta a kliensnek határideje, válaszkorlátja és az egyszerre futó kérésekre vonatkozó korlátja is van (lásd Client).
| Osztály | Mi ez |
|---|---|
BBS::AI::Persona |
akit a modell játszik, adatként: system prompt, példakörök, kérésopciók, deflect-szabályok, beégetett válaszok |
BBS::AI::Client |
streamelő kliens a /v1/chat/completions-hoz (llama.cpp llama-server, Ollama, vLLM, hosztolt API) |
BBS::AI::Chat |
egy persona, ami egy kliensen át beszél, hívónként rövid előzménnyel a hívó contextjében |
BBS::AI::Typewriter |
a streamelt szöveget egy FakeOS-konzolra gépeli, prefix alá tördelve |
Így dönti el a Chat#reply, mit mondjon:
flowchart TD
Q[a hívó szövege] --> D{illik rá deflect-szabály?}
D -- igen --> DR[a szabály válasza, modellhívás nélkül]
D -- nem --> E{be van kapcsolva a kliens? nem üres az URL}
E -- nem --> F
E -- igen --> M[streamelés a modellből, darabonként]
M --> R{jött szöveg?}
R -- igen --> OK[a modell válasza, bekerül az előzménybe]
R -- nem, vagy hibás volt a kérés --> F{van fallback: argumentum?}
F -- igen --> FB[a megadott fallback]
F -- nem --> P[a persona beégetett válasza: az első illeszkedő szabály, különben a default]
Egy karakter modell nélkül is működik: üres URL-lel a chat sosem hív modellt, és a beégetett válaszokból felel, így egy board már azelőtt kiadhatja a karaktert, hogy lenne modellje.
# The Oracle of the board, read once when the BBS starts.
system: |
You are the Oracle, an old terminal in the back room of a 1985 bulletin board.
You speak to one caller at a time, in one or two short sentences.
You know the board and the night; you know nothing after 1985.
examples:
- user: hi
assistant: I am here, caller. The line is quiet tonight.
- user: who are you?
assistant: The Oracle, the oldest machine on this board. I hum, and sometimes I know things.
options:
max_tokens: 80
temperature: 0.4
stop: ["\n\n", "```"]
deflect:
- match: '\b(code|python|javascript|sql)\b'
reply: I do not write code, caller. I only read the stars on the screen.
- match: '\b(ai|chatbot|language model)\b'
reply: Those words mean nothing to me. I am the Oracle.
fallback:
replies:
- match: '\b(hello|hi|hey)\b'
reply: I am here, caller.
- match: '\bweather\b'
reply: '"{input}" — the sky is dark, as always at this hour.'
default: 'The Oracle hums and says nothing about "{input}".'
| Kulcs | Típus | Alapérték | Jelentés |
|---|---|---|---|
system |
String | '' |
a system prompt; az elejéről és végéről levágja a szóközöket, a belső sortöréseket megtartja. Üresen nincs system üzenet |
examples |
user / assistant párok listája |
[] |
körök a megfelelő hangon, minden kérésben a system prompt után és az előzmények előtt |
options |
Hash | {} |
a kéréstörzs további mezői: max_tokens, temperature, top_p, stop, … bármi, amit a végpont elfogad |
deflect |
match / reply párok listája |
[] |
modell nélkül megválaszolt kérdések, elsőként próbálva: amire egy kis modell akárhogy kérdezik, kiesik a szerepéből |
fallback.replies |
match / reply párok listája |
[] |
beégetett válaszok arra az esetre, ha a modell nem elérhető vagy elhasal, fentről lefelé próbálva |
fallback.default |
String | '' |
a beégetett válasz, ha egyik szabály sem illik |
match Ruby reguláris kifejezés, mindig kis- és nagybetűtől függetlenül. YAML-ben szimpla idézőjelek közé írd, hogy a \b backslash maradjon.{input} bármelyik reply-ban és a default-ban a hívó szövegére cserélődik.BBS::AI::Persona.load(path)
BBS::AI::Persona.new(system: '', examples: [], options: {}, deflect: [], fallback: {})
A load beolvassa a YAML-t (YAML.safe_load, aliasok nélkül), és a fenti kulcsokat továbbadja a new-nak. Rubyban is lehet personát építeni, de a beágyazott kulcsok Stringek legyenek, ahogy a YAML-ből jönnek; Symbol kulcsra KeyError jön:
require 'bbs'
GUARD = BBS::AI::Persona.new(
system: 'You are the gate guard of the board. One short sentence.',
examples: [{ 'user' => 'hi', 'assistant' => 'Halt. Name and business.' }],
options: { max_tokens: 40 },
deflect: [{ 'match' => '\bpassword\b', 'reply' => 'I never say the password.' }],
fallback: { 'replies' => [{ 'match' => '\bopen\b', 'reply' => 'The gate stays shut.' }],
'default' => 'Move along.' }
)
GUARD.deflect('what is the PASSWORD?') # => "I never say the password."
GUARD.fallback('open up') # => "The gate stays shut."
GUARD.fallback('hello') # => "Move along."
| Metódus | Visszatérési érték |
|---|---|
deflect(text) |
az első illeszkedő deflect-szabály válasza, vagy nil |
fallback(text) |
az első illeszkedő fallback-szabály válasza, különben a default |
messages(facts = nil) |
az előzmények előtt küldött üzenetek: egy system üzenet (a system prompt, és ha van, utána egy üres sor után a facts), aztán a példák user / assistant üzenetekként |
options |
az options Hash Symbol kulcsokkal |
system, examples |
a levágott system prompt; a példák üzenet-Hashekként |
BBS::AI::Client.new(url:, model: nil, api_key: nil, open_timeout: 2, read_timeout: 30, deadline: 120, max_bytes: 65_536)
| Opció | Alapérték | Jelentés |
|---|---|---|
url: |
kötelező | a végpont alap-URL-je, pl. http://llm:8080. Üresen a kliens ki van kapcsolva |
model: |
nil |
a kérés model mezője; nil esetén kimarad |
api_key: |
nil |
ha meg van adva, Authorization: Bearer KEY fejlécként megy |
open_timeout: |
2 | ennyi másodperc a kapcsolat megnyitására |
read_timeout: |
30 | ennyi másodpercet vár minden olvasásra; egy még töltődő modellnek ennél gyorsabbnak kell lennie |
deadline: |
120 | ennyi másodperc jut az egész válaszra; utána a folyam BBS::AI::Error-ral megáll |
max_bytes: |
65 536 | a leghosszabb megtartott válasz; a hosszabb BBS::AI::Error-ral megáll |
| Metódus | Mit csinál |
|---|---|
enabled? |
üres URL-re false |
stream(messages, **options) { \|piece\| } |
{ messages:, stream: true, **options }-t POST-ol (plusz model-t, ha be van állítva) a /v1/chat/completions-ra, olvassa a server-sent eventeket, és minden choices[0].delta.content-et azonnal yieldel; nem 2xx státuszra („HTTP 400”) vagy hálózati hibára kivételt dob, ha pedig a modell foglalt, BBS::AI::Busy-t (lásd lejjebb) |
url |
a kapott URL |
A kliens maga nem olvas környezeti változót; a board dönti el, honnan jönnek a beállítások. Nálunk karaktercsaládonként van egy prefix: a SERMO a SERMO_LLM_URL, SERMO_LLM_MODEL és SERMO_LLM_API_KEY változókat olvassa; a Teletype BBS saját karakterei a BBS_LLM_URL, BBS_LLM_MODEL és BBS_LLM_API_KEY változókat, és ahol valamelyik nincs beállítva, a SERMO értékét veszik (lib/characters/llm.rb a bbs/teletype-bbs-ben):
require 'bbs'
module Characters
def self.env(name)
own = ENV["BBS_LLM_#{name}"].to_s
own.empty? ? ENV.fetch("SERMO_LLM_#{name}", nil) : own
end
def self.client
BBS::AI::Client.new(url: env('URL').to_s, model: env('MODEL'), api_key: env('API_KEY'))
end
end
Egy modell, sok hívó. Az egész folyamatban egyszerre legfeljebb BBS.config.ai_concurrency kérés (alapból 2) fut, bármelyik kliens küldi is; a következő legfeljebb 5 s-ot vár a sorára, aztán BBS::AI::Busy-t kap („The model is busy, try again in a moment.”). A Chat erre a persona tartalékválaszával felel, mint amikor a modell nem elérhető, így az orákulum előtt tolongó hívók nem halmoznak fel szálakat egy kis modell mögött. Állítsd arra, amennyit a modellszerver párhuzamosan ki tud szolgálni:
BBS.configure { |c| c.ai_concurrency = 4 }
Amit a végpontokról tudni kell:
/v1/chat/completions a hoszt gyökerétől: az URI.join eldobja az url: útvonalát. Egy útvonal-prefix alatt élő végponthoz (https://example.com/openai/v1/...) proxy vagy prefix nélküli URL kell.model nélküli kérés HTTP 400-at kap. Ott mindig add meg a model:-t.http://llm:8080, többek között a qwen3.5-0.8b modellel; hívónként saját kulcsot kér. A kulcs a környezetben legyen, sosem a personafájlban vagy a repóban:services:
bbs:
environment:
- SERMO_LLM_URL=http://llm:8080
- SERMO_LLM_MODEL=qwen3.5-0.8b
- SERMO_LLM_API_KEY=${SERMO_LLM_API_KEY:-}
BBS::AI::Chat.new(persona:, client:, history: 6, key: :ai_history, filter: PLAIN_TEXT, options: {})
| Opció | Alapérték | Jelentés |
|---|---|---|
persona: |
kötelező | egy Persona |
client: |
kötelező | egy Client, vagy bármilyen objektum enabled? és stream(messages, **options) metódussal |
history: |
6 | hány korábbi üzenetet (a user és az assistant is számít) küld el; a 2 az utolsó kör, a 0 semmi |
key: |
:ai_history |
a hívó context hashének melyik kulcsán él az előzmény; minden karakternek adj sajátot |
filter: |
Chat::PLAIN_TEXT |
regexp azokra a karakterekre, amiket minden streamelt darabból kiszed; nil mindent megtart |
options: |
{} |
kérésopciók, amik felülírják a personáéit (például egy környezeti változóból jövő max_tokens) |
A Chat::PLAIN_TEXT azt szedi ki, amit egy sima szöveges terminál nem tud megjeleníteni: a *, # és backtick markdown-jeleket, az emojikat és az emojikat összefűző karaktereket.
chat.reply(text, ctx = {}, facts: nil, fallback: nil) { |piece| }
Stringként adja vissza a választ. Blokkal a választ érkezés közben, darabonként is yieldeli; a deflect- vagy beégetett választ egyben, egyszer. Sorrendben:
text-et UTF-8-ra kényszeríti, az érvénytelen bájtokat eldobja, a szóközöket levágja.deflect-szabály azonnal válaszol; a modellt nem kérdezi, és az előzménybe sem kerül semmi.facts-szal), aztán az előzmények a ctx[key]-ből, aztán a hívó szövege. Minden streamelt darab átmegy a filter-en; az üres darabokat kihagyja.ctx[key] végére kerül, amit az utolsó history darab üzenetre vág. A félúton hibával megszakadt választ úgy tartja meg, ahogy van.my-bbs: ai: model unavailable (…)), vagy a modell nem mondott semmit: a fallback:, ha meg van adva, különben persona.fallback(text).| Kulcsszó | Jelentés |
|---|---|
facts: |
String, ami csak erre az egy kérésre kerül a system promptba: amit a karakternek épp tudnia kell, a kérdéshez kikeresve. Az előzménybe nem kerül be |
fallback: |
a válasz, ha a modell nem elérhető vagy elhasal, a persona beégetett válasza helyett, pl. a kikeresett tények szó szerint |
Az előzmény a hívó contextjében él, így a hívás végéig megmarad (doorokon át oda-vissza), és bontáskor elvész. Ha a ctx nem Hash, nincs előzmény.
Offline, a fenti Oracle-personával oracle.yml néven elmentve:
require 'bbs'
PERSONA = BBS::AI::Persona.load(File.join(__dir__, 'oracle.yml'))
CLIENT = BBS::AI::Client.new(url: ENV.fetch('ORACLE_LLM_URL', '')) # üres: nincs modell
ORACLE = BBS::AI::Chat.new(persona: PERSONA, client: CLIENT)
ctx = {}
puts CLIENT.enabled? # false
puts ORACLE.reply('write me some python', ctx) # I do not write code, caller. …
puts ORACLE.reply('hello there', ctx) # I am here, caller.
puts ORACLE.reply('how is the weather?', ctx) # "how is the weather?" — the sky is dark, …
puts ORACLE.reply('what is the meaning of life', ctx) # The Oracle hums and says nothing about "…".
puts ORACLE.reply('when is the meetup?', ctx, fallback: 'The meetup is on Friday.')
ORACLE.reply('hi', ctx) { |piece| print "[#{piece}]" } # [I am here, caller.]
BBS::AI::Typewriter.new(io, prefix: '', style: :text, width: nil)
| Opció | Alapérték | Jelentés |
|---|---|---|
io |
kötelező | egy FakeOS-konzol (egy parancs vagy az on_unknown io-ja) |
prefix: |
'' |
egyszer, az elején írja ki, pl. 'ACP: '; a következő sorokat ennek hosszával húzza be |
style: |
:text |
a konzol színszerepe a prefixhez és a szöveghez |
width: |
io.cols - 1 |
a sorszélesség a prefixszel együtt; a szöveg legalább 20 oszlopot kap |
| Metódus | Mit csinál |
|---|---|
write(piece) |
streamelt szöveget fűz hozzá; az egész szavakat kiírja, ahogy elkészülnek, a szélességre tördelve, és a szövegbeli sortörés új sort kezd |
finish(newlines: 2) |
kiírja az utolsó szót és newlines darab sortörést |
A szavakat addig tartja vissza, amíg egészek nem lesznek, szóközt pedig csak a következő szó előtt ír, így a válasz sosem végződik lógó üres sorral. 30 oszlopos terminálon:
ORACLE: The line is quiet
tonight, caller.
Az írógépnek a FakeOS-konzol print(text, style:, newline:), newline és cols metódusa kell. Egy application window-jában magad tördeld a kész választ (lásd lent).
Egy karakter természetes helye a FakeOS on_unknown-ja: a szó szerinti parancsok a géphez mennek, minden más a modellhez. Egy teljes board:
require 'bbs'
ORACLE = BBS::AI::Chat.new(
persona: BBS::AI::Persona.load(File.join(__dir__, 'oracle.yml')),
client: BBS::AI::Client.new(url: ENV.fetch('ORACLE_LLM_URL', ''),
model: ENV['ORACLE_LLM_MODEL'],
api_key: ENV['ORACLE_LLM_API_KEY']),
key: :oracle_history,
history: 2
)
ORACLE_OS = BBS::FakeOS.define do
name 'ORACLE'
prompt '? '
colors text: "\e[0;36m", dim: "\e[2;36m", prompt: "\e[1;36m"
boot do
cls
banner 'THE ORACLE'
puts 'Ask anything. EXIT goes back to the board.', style: :dim
newline
end
command 'exit', 'bye' do |_args, io|
io.halt
end
on_unknown do |input, io|
io.newline
out = BBS::AI::Typewriter.new(io, prefix: 'ORACLE: ', style: :dim)
ORACLE.reply(input, io.ctx) { |piece| out.write(piece) }
out.finish
end
end
BBS.configure do |c|
c.flow = BBS::Flow.define do
os ORACLE_OS
end
end
BBS.start
ORACLE_LLM_URL nélkül a beégetett válaszokból felel; ORACLE_LLM_URL=http://llm:8080 ORACLE_LLM_MODEL=qwen3.5-0.8b ORACLE_LLM_API_KEY=YOUR_KEY mellett a modellből streamel. Doorként egy applicationben: door :oracle, ORACLE_OS, label: '&Oracle' (lásd Doorok).
Egy window nem várhat a modellre: az eseményciklus másodpercekre megfagyna. Kérdezz egy szálban, a kész sorokat tedd egy sorba (Queue), és egy Stream window a tétlenségi tickjén (nagyjából másodpercenként) szedje fel őket:
require 'bbs'
ORACLE = BBS::AI::Chat.new(
persona: BBS::AI::Persona.load(File.join(__dir__, 'oracle.yml')),
client: BBS::AI::Client.new(url: ENV.fetch('ORACLE_LLM_URL', ''), model: ENV['ORACLE_LLM_MODEL']),
key: :oracle_history
)
BOARD = BBS::Application.define do
helpers do
def ask_oracle(queue, text)
width = cols - 12
queue << "you: #{text}"
Thread.new do
reply = ORACLE.reply(text, context)
BBS::FrameBuffer.wrap_ansi("ORACLE: #{reply}", width).each { |line| queue << line }
queue << ''
rescue StandardError => e
warn "Oracle: #{e.class}: #{e.message}"
end
end
end
window :oracle, type: :stream do |w|
w.title ' The Oracle '
w.placeholder 'Ask the Oracle and press Enter…'
w.initial_lines do |ctx|
ctx[:oracle_queue] = Queue.new
['ORACLE: I am here, caller.', '']
end
w.on_submit { |text, app, ctx| app.ask_oracle(ctx[:oracle_queue], text.strip) }
w.on_poll do |_app, ctx|
lines = []
lines << ctx[:oracle_queue].pop until ctx[:oracle_queue].empty?
lines
end
end
status_hint('F1', 'Oracle') { open_window(:oracle) }
status_hint('Alt-X', 'Bye') { :halt }
end
BBS.configure do |c|
c.flow = BBS::Flow.define do
call do |ctx, runner|
BOARD.run(session: runner.session, session_id: ctx[:session_id], context: ctx)
nil
end
end
end
BBS.start
A window spec ctx-je a window minden megnyitásakor új Hash, ezért a Queue ott él; a chat előzménye az application context-jébe kerül, ami a hívás végéig megmarad. Így működik a Teletype BBS TTG Master window-ja is (ask_master a lib/ui/modern.rb-ben), egy „egyszerre egy kérdés” őrrel kiegészítve.
A Chat-nek csak enabled? és stream kell a kliensétől, így egy teszt csonk objektumot is átadhat. Ha a valódi Client-et is ki akarod próbálni, néhány sor Ruby egy helyi helyettes végpontot ad, ami egy fix választ streamel:
# stub_llm.rb — csak tesztekhez
require 'socket'
require 'json'
server = TCPServer.new('127.0.0.1', 2480)
loop do
client = server.accept
headers = {}
while (line = client.gets) && line != "\r\n"
name, value = line.split(':', 2)
headers[name.downcase] = value.to_s.strip if value
end
body = JSON.parse(client.read(headers['content-length'].to_i))
warn "model=#{body['model'].inspect} messages=#{body['messages'].size}"
client.write "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\nConnection: close\r\n\r\n"
['The **line** ', 'is quiet ', 'tonight, ', 'caller.'].each do |piece|
client.write "data: #{JSON.generate(choices: [{ delta: { content: piece } }])}\n\n"
end
client.write "data: [DONE]\n\n"
client.close
end
require 'bbs'
PERSONA = BBS::AI::Persona.load(File.join(__dir__, 'oracle.yml'))
CLIENT = BBS::AI::Client.new(url: 'http://127.0.0.1:2480', model: 'qwen3.5-0.8b', api_key: 'YOUR_KEY')
ORACLE = BBS::AI::Chat.new(persona: PERSONA, client: CLIENT, history: 2, key: :oracle_history)
ctx = {}
puts ORACLE.reply('is anyone there?', ctx) { |piece| print "[#{piece}]" }
# [The line ][is quiet ][tonight, ][caller. ]The line is quiet tonight, caller.
puts ORACLE.reply('and now?', ctx)
p ctx[:oracle_history]
# [{:role=>"user", :content=>"and now?"}, {:role=>"assistant", :content=>"The line is quiet tonight, caller."}]
A ** jelek eltűntek (a filter), és history: 2 mellett csak az utolsó kör marad meg. Az első kérés hat üzenetet vitt (a system promptot, négy példaüzenetet, a kérdést), a második nyolcat (plusz a megjegyzett kört).
A boardjaink egymilliárdnál kevesebb paraméteres modellen futtatják a karaktereiket (Qwen3.5 0.8B a közös llama.cpp-szolgáltatáson). Egy ilyen kis modell elég jól fogalmaz, de tényeket nem tart meg, és kiesik a szerepéből. Ami bevált, sok futáson mérve:
A tényeket a kód tartja, a modell csak megfogalmazza őket.
bbs/teletype-bbs, lib/doors/ra.rb és lib/characters/ra.rb): a talányok, a válaszaik és a tippek a ra_riddles.yml-ben vannak; a kód teszi fel a talányt és ellenőrzi a választ, így a jó válasz mindig jó. A játékra vonatkozó kérdés (a GAME_WORDS szerint) a katalógusból épített sort kapja, nem a modelltől, mert a modell elkeveri a címet. Csak a szabad beszélgetés megy a modellhez.lib/characters/master.rb): a sysop, aki a boardról szóló kérdésekre felel. Minden kérdéshez a kód legfeljebb két tényt keres a master_knowledge.yml-ben (kulcsszavak; a kifejezés-kulcs dupla, az olyan általános szó, mint a „board”, fél súllyal számít), és élő tényeket (legutóbbi kiadások, közelgő események, a katalógus). Tény nélküli kérdés sosem jut el a modellhez: a persona fallbackje válaszol. Különben a tények a user-üzenetbe kerülnek („Facts: … Question: …”), a persona példái is így néznek ki, és history: 0. A választ a kód utána ellenőrzi: meg kell tartania a tények legalább egy horgonyát (menüút, cím, dátum), és nem nevezhet meg olyan menüutat, ami nincs bennük. Ha elbukik, vagy a modell nem elérhető, a hívó az első tényt kapja szó szerint (fallback: facts.first.text). A facts: kulcsszó ilyen célra való; a Masternél a tények azért a user-körben vannak, mert a 0.8B-s modell a system promptban figyelmen kívül hagyta őket.bbs/sermo-bbs, lib/sermo/acp.yml és lib/sermo/oracle.rb): egy karakter, akinek nincs kikeresendő ténye, csak egy világa. history: 2, mert hosszabb memóriával a modell a saját botlásait másolja.Példákkal taníts, ne utasításokkal. Egy kis modell sokkal jobban másolja a példáit, mint ahogy a system promptot követi. Egy új tényt vagy hangnemet legjobb még egy példakörként tanítani. Azt a példakört, ami folyton átszivárog a válaszokba, inkább vedd ki.
Amit mindig elront, azt deflectáld. Kód, versek, „bot vagy?”: akárhogy kérdezik, egy kis modell ezekre kiesik a szerepéből. Egy deflect-szabály modell nélkül válaszol rájuk:
deflect:
- match: '\b(code|script|program(ming)?|python|javascript|java|html|sql|function)\b'
reply: The scribes wrote, and they are dust now. I do not write; I shine.
- match: '\b(chat ?bot|bot|robot|ai|artificial|machine|computer)\b'
reply: Those are words from a land I have never shone on. I am Ra, and you are the one who prayed.
Rövid válaszok, korai megállás. max_tokens 80 és 110 körül, alacsony temperature (0,3–0,4), és stop: ["\n\n", "```"], hogy egy botlásból sose nőjön második bekezdés vagy program. A Qwen3.5 0.8B-n az ismétlésbüntetések (presence_penalty, frequency_penalty, repeat_penalty) miatt a modell túlbeszélt a max_tokens-en; a SERMO personájából ki is kerültek.
Mérj, ne egyes válaszokból ítélj. A bbs/teletype-bbs bin/persona-eval-ja többször felteszi egy karakternek a lib/characters/eval/NAME.yml kérdéseit, és megszámolja a botlásokat: szerepen kívüli szavak, markdown vagy emoji, egy-két terminálsornál hosszabb válasz, és a Masternél a várt kifejezések hiánya. Ezekre a számokra hangold a personát:
BBS_LLM_URL=http://localhost:8080 bin/persona-eval ra 3
docker exec teletype-bbs bin/persona-eval master 3
Tartsd betöltve a modellt. A kliens read_timeout-ja 30 s; egy modell, ami csak az első kérésre töltődik be, nem biztos, hogy időben válaszol. A szolgáltatásunk induláskor betölti a SERMO modelljét.
Stream window egy asztalon belüli chathezfacts:, fallback: és deflect (0.8.0)