AI Zone Admin Forum Add your forum

NEWS: survey on 3000 US and UK consumers shows it is time for chatbot integration in customer service!read more..

RiveScript Tutorial

Since others have expressed an interest in having a RiveScript tutorial, I’ve spent the last couple days putting one together.

You can read it here:

It covers just about all the features of RiveScript and provides code examples for all of them. It starts you out slow (making sure you can write and run your RiveScript code) and then leaves you to your own devices with code snippits that show what all can be done.

If you’ve been wanting to learn how to write RiveScript code, give this tutorial a read-through and let me know if any improvements can be made to it. If any parts are confusing, vague or could be elaborated on, I’ll be happy to fix them!

This tutorial will eventually be included in the Perl RiveScript distribution, so that page would be mirrored on the CPAN.


  [ # 1 ]

Wow! I’m surprised that nobody has responded to this yet!

I’ve finally had the time to read through the tutorial, and I have to say great work! If I had more time to do so, i’d love to take a look at the PERL source, and attempt to make a PHP port of the engine, but sadly, I’ve way too many irons in the fire. downer


  [ # 2 ]


I recently gave this RiveScript tutorial a proof read,
and in my opinion, it is packed with valuable info for
chatter robot masters.


  [ # 3 ]

Very nicely done, Noah. Some great information! Thanks!


  [ # 4 ]

Yes, just started really getting to grips with Rivescript and it is a great and well written tutorial.

Love the features Noah’s included in Rivescript, particularly the ability to include Perl objects. Adds so much potential power (and does for me what the inlcusion of c# did with Verbots).

Also is a very clear approach to bot development.


  [ # 5 ]

Hi, I am trying to follow instructions of the tutorial, but I am stopped on this part :

Conditions are used to compare variables to values. You can also compare variables to other variables. Here is a more advanced way of telling the bot what your name is:

  + my name is *
  * <formal>  == <bot name> => Wow, we have the same name!<set name=<formal>>
  * <get name> == undefined => <set name=<formal>>Nice to meet you! <get name>
  - <set oldname=<get name>><set name=<formal>>
  ^ I thought your name was <get oldname>?


I have copied in my file and run it. But there is something wrong..

You> my name is Pavel
Bot> Nice to meet you! Pavel
You> my name is Jhon
Bot> >I thought your name was <get name!

it seems the “oldname” variable was not assigned any value. Can someone tell me whether there is an errata in the tutorial or not?

Thanks in advance




  [ # 6 ]

Yeah, that is a typo… <get> doesn’t currently work inside of <set> in any of the existing RiveScript libraries. :(

The reason is I’m using a simple “find-and-replace” system for dealing with tags, and <set> tags are handled earlier than <get> tags (so that “<set name=<formal>>Hello, <get name>” works as expected).

If I come up with an efficient algorithm to process tags from left to right (instead of just doing one tag at a time in a predetermined order), I’ll update the libraries so that using <get> inside of <set> would work.

Order of tag processing is currently outlined here:


  [ # 7 ]

Wouldn’t it be better to adopt an “inside-out” algorithm, where you “tunnel down” to the innermost nested element, then work back out? This method may incur more overhead, but at least it follows a logical progression, to my way of thinking. smile


  [ # 8 ]

Thanks Dave

I was actually finding a way to tackle this problem over the last couple hours. At first I was trying a tokenizing method, so for example:

MESSAGE: <set oldname=<get name>>I thought your name was <get oldname>?
TOKENS: [’<’, ‘set oldname=’, ‘<’, ‘get name’, ‘>’, ‘>’, ‘I thought your name was ‘, ‘<’, ‘get oldname’, ‘>’, ‘?’]

And then it would scan through and when it finds a closing tag (which would necessarily be the most deeply embedded tag, the <get name> in this case) it would try to “fix” it in the reply by substituting that variable in, and go from there. It got really hairy and out of control.

So instead I found a simpler method, using an iterative regexp. Github gist of the new algorithm:

Basically it will make multiple passes, and search for tags that don’t contain other tags, so in the case of “<set oldname=<get name>>”, only “<get name>” will match the regexp and it will be handled on the first pass. And then the “<set oldname=xxx>” will be handled on the second pass, and so-on.

Anyway, @Pavél, which programming language are you using? I’ve implemented this fix in the Python and Perl versions of RiveScript, which you can get from their GitHub URLs. I’ll tackle the JavaScript version next, but first I need to write unit tests for the JS version to make sure I don’t break anything (the Perl and Python versions already had unit tests so I feel confident enough that they’re not broken).


  [ # 9 ]

As an update:

* I ported over the Python unit tests to the JS version, and found some bugs that got fixed.
* I implemented this new tag processing algorithm in the JS version (v1.0.5, will probably go up on npm before too long, since all the bugs I found when writing the unit tests means I don’t know how anybody is using this in production raspberry)
* Also I brought over my experimental UTF-8 support for the JS version (Perl & Python aren’t the only ones having all the fun anymore)

The only version that doesn’t have UTF-8, unit tests, or the new tag algorithm is the Java version. wink


  [ # 10 ]

Thanks for this, just installed rivescript today (Python).

I need to save variables to a file so I can create new ones. Basically I want the bot to respond to * is * with the ability to save that value to that variable.

I notice this is already possible in the Rivescript.set_variable() method, and the Rivescript.set_uservars() method, and there is a Rivescript.write() method that can write variables and values to a file.

But does it write bot variables as well as user variables?

I could also use something that could somehow bind an array to a variable, something like a. “is array” and a “like array”. That way one variable can be a bunch of things and also be like a bunch of things, based on somewhat natural input.


  [ # 11 ]

For saving user variables to disk, write that code yourself. wink It’s outside the scope of the RiveScript module.

It’s easy to do in Python by just saving it as JSON to a file:

import codecs
import json

# write
vars rs.get_uservars(name)

# read
vars json.loads(
keyvalue in vars.items():

The write() method will save bot variables to disk, but not user variables. This function was designed to help with programmatically modified RiveScript (e.g. you could write code that loads RiveScript data from disk, adds new replies in-memory into the object, i.e. with stream(), and later write() all of the in-memory replies back to a file). Since bot variables are defined in a .rive file, write() will put them back when saving again (same with global vars, substitutions, and everything else that would be defined in a .rive file). It doesn’t save user variables because those don’t belong in .rive files.

Array variables for users aren’t supported in RiveScript at this time. I may look into adding them at some point, but arrays are difficult to work with without making the RiveScript syntax look really hairy (e.g. RiveScript is processed line-by-line, and logic like “for-each loops” won’t look very good wink ). I may implement them in the form of a “set” though, which would work like sets in Python (you’d be able to add, remove, and check if an item is in the set, but not iterate over all items because that would make for some ugly syntax).


  [ # 12 ]

Hey, thanks for replying.

Ok, writing it myself seems easy enough.

As for the array idea, looking at aiml 2.0 it seems they have something like this set up with their AIML Sets and AIML Maps functionality.
Unfortunately aiml 2.0 interpreters are few and far between it seems, and nothing for python. :-(

Would it be at all possible to implement this functionality in Rivescript? I’m not sure, t seems hard to do without looping.
Apart from that, and loops, Rivescript seems to have all the functionality of AIML 2.0,  at least to my eyes.

Anyway thanks again.


  [ # 13 ]

You know what, forget everything I said above.

I’m still getting used to how all this works. It seems Rivescript is perfectly suited to do everything AIML 2.0 can do, with a little bit of work.

I’m still trying to wrap my head around topics, I want to use them extensively but the tutorial kinda stops at that point.
Ideally I’d want a mostly topic based structure, but allow some general topics to inherit into the more specific topics so the conversation does not completely become about one thing.

The topics should have a few topical values like: he/she/it
If the topic is Barack Obama, then “he” would always refer to him and so on.

From what I understand all this is possible right now with Rivescript, I’m just not totally sure how…. tongue laugh


  [ # 14 ]

You could make a topic that inherits the default (“random”) topic, like

topic obama inherits random

When a topic inherits another one, all replies in the current topic have a higher matching priority than replies in an inherited one (i.e. the default “random” triggers won’t be tested unless no reply in the “obama” topic matched the user’s message yet). So with this you could have a topic which is basically the “random” topic except you override a few triggers (change the meaning of “he” in triggers such as “he *” for example).


  [ # 15 ]

Thanks again, I’m getting the hang of this now, inherit and include and the difference.
Ok LAST tutorial question I promise.

How do you make a new user variable?

Obviously this is for teaching, If I want to change an existing user variable like my user name, user age or user girl/boyfriend I can do so since those variables already exist, so all I need to do change them.

But telling the bot to learn a new one presents an issue.
Obviously I can make a python script that simply writes another variable into the relevant .rive file, but that wouldn’t exist until I restarted the bot.

Another option would be to write it into a vars.json file and read it into memory with the code you posted above.
But then I’m reloading the full brain everytime I make a new Variable.

Optionally I could make it an external .json file and read that one into memory. Would this work? When I save the brain at the end of the session would this new variable now be a part of var.json?

Is there a better more streamlined way to do this? 


 1 2 > 
1 of 2
  login or register to react