Chapter 12. Getting chatty (dialog engines)

This chapter covers

  • Understanding four chatbot approaches
  • Finding out what Artificial Intelligence Markup Language is all about
  • Understanding the difference between chatbot pipelines and other NLP pipelines
  • Learning about a hybrid chatbot architecture that combines the best ideas into one
  • Using machine learning to make your chatbot get smarter over time
  • Giving your chatbot agency—enabling it to spontaneously say what’s on its mind

We opened this book with the idea of a dialog engine or chatbot NLP pipeline because we think it’s one of the most important NLP applications of this century. For the first time in history we can speak to a machine in our own language, and we can’t always tell that it isn’t human. Machines can fake being human, which is a lot harder than it sounds. There are several cash prize competitions, if you think you and your chatbot have the right stuff:

Beyond the pure fun and magic of building a conversational machine, beyond the glory that awaits you if you build a bot that can beat humans at an IQ test, beyond the warm fuzzy feeling of saving the world from malicious hacker botnets, and beyond the wealth that awaits you if you can beat Google and Amazon at their virtual assistant games—the techniques you’ll learn in this chapter will give you the tools you need to get the job done.

The 21st century is going to be built on a foundation of AI (artificial intelligence) that assists us. And the most natural interface for AI is natural language conversation. For example, Aira.io’s chatbot Chloe is helping to interpret the world for people who are blind or have low-vision. Other companies are building lawyer chatbots that save users thousands of dollars (or pounds) on parking tickets and hours of courtroom time. And self-driving cars will likely soon have conversational interfaces similar to Google Assistant and Google Maps to help you get where you want to go.

12.1. Language skill

You finally have all the pieces you need to assemble a chatbot—more formally, a dialog system or dialog engine. You’ll build an NLP pipeline that can participate in natural language conversations.

Some of the NLP skills you’ll use include

  • Tokenization, stemming, and lemmatization
  • Vector space language models such as bag-of-words vectors or topic vectors (semantic vectors)
  • Deeper language representations such as word vectors or LSTM thought vectors
  • Sequence-to-sequence translators (from chapter 10)
  • Pattern matching (from chapter 11)
  • Templates for generating natural language text

With these tools, you can build a chatbot with interesting behavior.

Let’s make sure we’re on the same page about what a chatbot is. In some communities, the word “chatbot” is used in a slightly derogatory way to refer to “canned response” systems.[6] These are chatbots that find patterns in the input text and use matches on those patterns to trigger a fixed, or templated, response.[7] You can think of these as FAQ bots that only know the answers to basic, general questions. These basic dialog systems are useful mainly for automated customer service phone-tree systems, where it’s possible to hand off the conversation to a human when the chatbot runs out of canned responses.

6

Wikipedia “Canned Response,” https://en.wikipedia.org/wiki/Canned_response.

7

“A Chatbot Dialogue Manager” by A.F. van Woudenberg, Open University of the Netherlands, http://dspace.ou.nl/bitstream/1820/5390/1/INF_20140617_Woudenberg.pdf.

But this doesn’t mean that your chatbot needs to be so limited. If you’re particularly clever about these patterns and templates, your chatbot can be the therapist in a convincing psychotherapy or counseling session. All the way back in 1964, Joseph Weizenbaum used patterns and templates to build the first popular chatbot, ELIZA.[8] And the remarkably effective Facebook Messenger therapy bot, Woebot, relies heavily on the pattern-matching and templated response approach. All that’s needed to build Turing prize-winning chatbots is to add a little state (context) management to your pattern-matching system.

8

Steve Worswick’s Mitsuku chatbot won the Loebner Prize (https://en.wikipedia.org/wiki/Turing_test), a form of the Turing Test, in 2016 and 2017 using pattern matching and templates. He added context or statefulness, to give Mitsuku a bit more depth. You can read about the other winners on Wikipedia (https://en.wikipedia.org/wiki/Loebner_Prize#Winners). Amazon recently added this additional layer of conversational depth (context) to Alexa and called it “Follow-Up Mode.”[9] You’ll learn how to add context to your own pattern-maching chatbots in this chapter.

9

12.1.1. Modern approaches

Chatbots have come a long way since the days of ELIZA. Pattern-matching technology has been generalized and refined over the decades. And completely new approaches have been developed to supplement pattern matching. In recent literature, chatbots are often referred to as dialog systems, perhaps because of this greater sophistication. Matching patterns in text and populating canned-response templates with information extracted with those patterns is only one of four modern approaches to building chatbots:

  • Pattern matching—Pattern matching and response templates (canned responses)
  • Grounding—Logical knowledge graphs and inference on those graphs
  • Search—Text retrieval
  • Generative—Statistics and machine learning

This is roughly the order in which these approaches were developed. And that’s the order in which we present them here. But before showing you how to use each technique to generate replies, we show you how chatbots use these techniques in the real world.

The most advanced chatbots use a hybrid approach that combines all of these techniques. This hybrid approach enables them to accomplish a broad range of tasks. Here’s a list of a few of these chatbot applications; you may notice that the more advanced chatbots, such as Siri, Alexa, and Allo, are listed alongside multiple types of problems and applications:

  • Question answering—Google Search, Alexa, Siri, Watson
  • Virtual assistants—Google Assistant, Alexa, Siri, MS paperclip
  • Conversational—Google Assistant, Google Smart Reply, Mitsuki Bot
  • Marketing—Twitter bots, blogger bots, Facebook bots, Google Search, Google Assistant, Alexa, Allo
  • Customer service—Storefront bots, technical support bots
  • Community management—Bonusly, Slackbot
  • Therapy—Woebot, Wysa, YourDost, Siri, Allo

Can you think of ways to combine the four basic dialog engine types to create chatbots for these seven applications? Figure 12.1 shows how some chatbots do it.

Let’s talk briefly about these applications to help you build a chatbot for your application.

Figure 12.1. Chatbot techniques used for some example applications

Question answering dialog systems

Question answering chatbots are used to answer factual questions about the world, which can include questions about the chatbot itself. Many question answering systems first search a knowledge base or relational database to “ground” them in the real world. If they can’t find an acceptable answer there, they may search a corpus of unstructured data (or even the entire Web) to find answers to your questions. This is essentially what Google Search does. Parsing a statement to discern the question in need of answering and then picking the right answer requires a complex pipeline that combines most of the elements covered in previous chapters. Question answering chatbots are the most difficult to implement well because they require coordinating so many different elements.

Virtual assistants

Virtual assistants, such as Alexa and Google Assistant, are helpful when you have a goal in mind. Goals or intents are usually simple things such as launching an app, setting a reminder, playing some music, or turning on the lights in your home. For this reason, virtual assistants are often called goal-based dialog engines. Dialog with such chatbots is intended to conclude quickly, with the user being satisfied that a particular action has been accomplished or some bit of information has been retrieved.

You’re probably familiar with the virtual assistants on your phone or your home automation system. But you may not know that virtual assistants can also help you with your legal troubles and taxes. Though Intuit’s TurboTax wizards aren’t very chatty, they do implement a complex phone tree. You don’t interact with them by voice or chat, but by filling in forms with structured data. So the TurboTax wizard can’t really be called a chatbot yet, but it’ll surely be wrapped in a chat interface soon, if the taxbot AskMyUncleSam takes off.[10]

10

Lawyer virtual assistant chatbots have successfully appealed millions of dollars in parking tickets in New York and London.[11] And there’s even a United Kingdom law firm where the only interaction you’ll ever have with a lawyer is through a chatbot.[12] Lawyers are certainly goal-based virtual assistants, only they’ll do more than set an appointment date: they’ll set you a court date and maybe help you win your case.

11

June 2016, “Chatbot Lawyer Overturns 160,000 Parking Tickets in London and New York,” The Guardian, https://www.theguardian.com/technology/2016/jun/28/chatbot-ai-lawyer-donotpay-parking-tickets-london-new-york.

12

Nov 2017, “Chatbot-based ‘firm without lawyers’ launched” blog post by Legal Futures: https://www.legalfutures.co.uk/latest-news/chatbot-based-firm-without-lawyers-launched.

Aira.io (http://aira.io) is building a virtual assistant called Chloe. Chloe gives blind and low-vision people access to a “visual interpreter for the blind.” During onboarding, Chloe can ask customers things such as “Are you a white cane user?” “Do you have a guide dog?” and “Do you have any food allergies or dietary preferences you’d like us to know about?” This is called voice first design, when your app is designed from the ground up around a dialog system. In the future, the assistance that Chloe can provide will be greatly expanded as she learns to understand the real world through live video feeds. And the “explorers” around the world interacting with Chloe will be training her to understand common everyday tasks that humans perform in the world. Chloe is one of the few virtual assistants designed entirely to assist and not to influence or manipulate.[13]

13

We rarely acknowledge to ourselves the influence that virtual assistants and search engines exert over our free will and beliefs. And we rarely care that their incentives and motivations are different from our own. These misaligned incentives are present not only in technology such as virtual assistants, but within culture itself. Check out Sapiens and Homo Deus by Yuval Noah Harari if you’re interested in learning about where culture and technology are taking us.

Virtual assistants such as Siri, Google Assistant, Cortana, and Aira’s Chloe are getting smarter every day. Virtual assistants learn from their interactions with humans and the other machines they’re connected to. They’re developing evermore general, domain-independent intelligence. If you want to learn about artificial general intelligence (AGI), you’ll want to experiment with virtual assistants and conversational chatbots as part of that research.

Conversational chatbots

Conversational chatbots, such as Worswick’s Mitsuku[14] or any of the Pandorabots,[15] are designed to entertain. They can often be implemented with very few lines of code, as long as you have lots of data. But doing conversation well is an ever-evolving challenge. The accuracy or performance of a conversational chatbot is usually measured with something like a Turing test. In a typical Turing test, humans interact with another chat participant through a terminal and try to figure out if it’s a bot or a human. The better the chatbot is at being indistinguishable from a human, the better its performance on a Turing test metric.

14

See the web page titled “Mitsuku Chatbot” (http://www.square-bear.co.uk/aiml).

15

See the web page titled “Pandorabots AIML Chatbot Directory” (https://www.chatbots.org).

The domain (variety of knowledge) and human behaviors that a chatbot is expected to implement, in these Turing tests, is expanding every year. And as the chatbots get better at fooling us, we humans get better at detecting their trickery. ELIZA fooled many of us in the BBS-era of the 1980s into thinking that “she” was a therapist helping us get through our daily lives. It took decades of research and development before chatbots could fool us again.

Fool me once, shame on bots; fool me twice, shame on humans.

Anonymous Human

Recently, Mitsuku won the Loebner challenge, a competition that uses a Turing test to rank chatbots.[16] Conversational chatbots are used mostly for academic research, entertainment (video games), and advertisement.

16

See the web page titled “Loebner Prize” (https://en.wikipedia.org/wiki/Loebner_Prize).

Marketing chatbots

Marketing chatbots are designed to inform users about a product and entice them to purchase it. More and more video games, movies, and TV shows are launched with chatbots on websites promoting them: [17]

17

Justin Clegg lists additional ones in his LinkedIn post: https://www.linkedin.com/pulse/how-smart-brands-using-chatbots-justin-clegg/.

Some virtual assistants are marketing bots in disguise. Consider Amazon Alexa and Google Assistant. Though they claim to assist you with things such as adding reminders and searching the web, they invariably prioritize responses about products or businesses over responses with generic or free information. These companies are in the business of selling stuff—directly in the case of Amazon, indirectly in the case of Google. Their virtual assistants are designed to assist their corporate parents (Amazon and Google) in making money. Of course, they also want to assist users in getting things done, so we’ll keep using them. But the objective functions for these bots are designed to steer users toward purchases, not happiness or well-being.

Most marketing chatbots are conversational, to entertain users and mask their ulterior motives. They can also employ question answering skills, grounded in a knowledge base about the products they sell. To mimic characters in a movie, show, or video game, chatbots will use text retrieval to find snippets of things to say from the script. And sometimes even generative models are trained directly on a collection of scripts. So marketing bots often employ all four of the techniques you’ll learn about in this chapter.

Community management

Community management is a particularly important application of chatbots because it influences how society evolves. A good chatbot “shepherd” can steer a video game community away from chaos and help it grow into an inclusive, cooperative world where everyone has fun, not just the bullies and trolls. A bad chatbot, such as the Twitter bot Tay, can quickly create an environment of prejudice and ignorance.[21]

21

Wikipedia article about the brief “life” of Microsoft’s Tay chatbot, https://en.wikipedia.org/wiki/Tay_(bot).

When chatbots go “off the rails,” some people claim they are merely mirrors or magnifiers of society. And there are often unintended consequences of any complicated system interacting with the real world. But because chatbots are active participants, imbued with motivations by developers like you, you shouldn’t dismiss them as merely “mirrors of society.” Chatbots seem to do more than merely reflect and amplify the best and the worst of us. They’re an active force, partially under the influence of their developers and trainers, for either good or evil. Because supervisors and managers cannot perfectly enforce any policy that ensures chatbots “do no evil,” it’s up to you, the developer, to strive to build chatbots that are kind, sensitive, and pro-social. Asimov’s “Three Laws of Robotics” aren’t enough.[22] Only you can influence the evolution of bots, using smart software and cleverly constructed datasets.

22

March 2014, George Dvorski, “Why Asimov’s Three Laws of Robotics Can’t Protect Us,” Gizmodo, https://io9.gizmodo.com/why-asimovs-three-laws-of-robotics-cant-protect-us-1553665410.

Some smart people at Arizona University are considering using their chatbot-building skills to save humanity, not from Evil Superintelligent AI, but from ourselves. Researchers are trying to mimic the behavior of potential ISIS terrorist recruits to distract and misinform ISIS recruiters. This may one day mean that chatbots are saving human lives, simply by chatting it up with people that intend to bring harm to the world.[23] Chatbot trolls can be a good thing if they troll the right people or organizations.

23

Customer service

Customer service chatbots are often the only “person” available when you visit an online store. IBM’s Watson, Amazon’s Lex, and other chatbot services are often used behind the scenes to power these customer assistants. They often combine both question answering skills (remember Watson’s Jeopardy training?) with virtual assistance skills. But unlike marketing bots, customer service chatbots must be well-grounded. And the knowledge base used to “ground” their answers to reality must be kept current, enabling customer service chatbots to answer questions about orders or products as well as initiate actions such as placing or canceling orders.

In 2016, Facebook Messenger released an API for businesses to build customer service chatbots. And Google recently purchased API.ai to create their Dialogflow framework, which is often used to build customer service chatbots. Similarly, Amazon Lex is often used to build customer service dialog engines for retailers and wholesalers of products sold on Amazon. Chatbots are quickly becoming a significant sales channel in industries from fashion (Botty Hilfiger) to fast food (TacoBot) to flowers.[24]

24

Therapy

Modern therapy chatbots, such as Wysa and YourDOST, have been built to help displaced tech workers adjust to their new lives.[25] Therapy chatbots must be entertaining like a conversational chatbot. They must be informative like a question answering chatbot. And they must be persuasive like a marketing chatbot. And if they’re imbued with self-interest to augment their altruism, these chatbots may be “goal-seeking” and use their marketing and influence skill to get you to come back for additional sessions.

25

You might not think of Siri, Alexa, and Allo as therapists, but they can help you get through a rough day. Ask them about the meaning of life and you’ll be sure to get a philosophical or humorous response. And if you’re feeling down, ask them to tell you a joke or play some upbeat music. And beyond these parlor tricks, you can bet that developers of these sophisticated chatbots were guided by psychologists to help craft an experience intended to increase your happiness and sense of well-being.

As you might expect, these therapy bots employ a hybrid approach that combines all four of the basic approaches listed at the beginning of this chapter.

12.1.2. A hybrid approach

So what does this hybrid approach look like?

The four basic chatbot approaches can be combined in a variety of ways to produce useful chatbots. And many different applications use all four basic techniques. The main difference between hybrid chatbots is how they combine these four skills, and how much “weight” or “power” is given to each technique.

In this chapter, we show you how to balance these approaches explicitly in code to help you build a chatbot that meets your needs. The hybrid approach we use here will allow you to build features of all these real world systems into your bot. And you’ll build an “objective function” that’ll take into account the goals of your chatbot when it’s choosing between the four approaches, or merely choosing among all the possible responses generated by each approach.

So let’s dive into each of these four approaches, one at a time. For each one, we build a chatbot that uses only the technique we’re learning. But in the end we show you how to combine them all together.

12.2. Pattern-matching approach

The earliest chatbots used pattern matching to trigger responses. In addition to detecting statements that your bot can respond to, patterns can also be used to extract information from the incoming text. You learned several ways to define patterns for information extraction in chapter 11.

The information extracted from your users’ statements can be used to populate a database of knowledge about the users, or about the world in general. And it can be used even more directly to populate an immediate response to some statements. In chapter 1, we showed a simple pattern-based chatbot that used a regular expression to detect greetings. You can also use regular expressions to extract the name of the person being greeted by the human user. This helps give the bot “context” for the conversation. This context can be used to populate a response.

ELIZA, developed in the late 1970s, was surprisingly effective at this, convincing many users that “she” was capable of helping them with their psychological challenges. ELIZA was programmed with a limited set of words to look for in user statements. The algorithm would rank any of those words that it saw in order to find a single word that seemed like the most important word in a user’s statement. That would then trigger selection of a canned response template associated with that word. These response templates were carefully designed to emulate the empathy and open-mindedness of a therapist, using reflexive psychology. The key word that had triggered the response was often reused in the response to make it sound like ELIZA understood what the user was talking about. By replying in a user’s own language, the bot helped build rapport and helped users believe that it was listening.

ELIZA taught us a lot about what it takes to interact with humans in natural language. Perhaps the most important revelation was that listening well, or at least appearing to listen well, is the key to chatbot success.

In 1995, Richard Wallace began building a general chatbot framework that used the pattern-matching approach. Between 1995 and 2002, his community of developers built the Artificial Intelligence Markup Language (AIML) to specify the patterns and responses of a chatbot. A.L.I.C.E. was the open source reference implementation of a chatbot that utilized this markup language to define its behavior. AIML has since become the de facto open standard for defining chatbot and virtual assistant configuration APIs for services such as Pandorabots. Microsoft’s Bot framework is also able to load AIML files to define chatbot behaviors. Other frameworks like Google’s Dialog-Flow and Amazon Lex don’t support import or export of AIML.

AIML is an open standard, meaning the language is documented and it doesn’t have hidden proprietary features locked to any particular company. Open source Python packages are available for parsing and executing AIML for your chatbot.[26] But AIML limits the types of patterns and logical structures you can define. And it’s XML, which means chatbot frameworks built in Python (such as Will and ChatterBot) are usually a better foundation for building your chatbot.

26

Because you have a lot of your NLP tools in Python packages already, you can often build much more complex pattern-matching chatbots just by building up the logic for your bot directly in Python and regular expressions or glob patterns.[27] At Aira, we developed a simple glob pattern language similar to AIML to define our patterns. We have a translator that converts this glob pattern language into regular expressions that can be run on any platform with a regular expression parser.

27

Glob patterns and globstar patterns are the simplified regular expressions you use to find files in DOS or Bash or pretty much any other shell. In a glob pattern, the asterisk or star (*) is used to represent any number of any characters. So *.txt will match any filenames that have “.txt” at the end (https://en.wikipedia.org/wiki/Glob_%28programming%29).

And Aira uses {{handlebars}} for our template specifications in this aichat bot framework (http://github.com/aira/aichat). The handlebars templating language has interpreters for Java and Python, so Aira uses it on a variety of mobile and server platforms. And handlebars expressions can include filters and conditionals that can be used to create complex chatbot behavior. If you want something even more straightforward and Pythonic for your chatbot templates, you can use Python 3.6 f-strings. And if you’re not yet using Python 3.6, you can use str.format(template, **locals()) to render your templates just like f-strings do.

12.2.1. A pattern-matching chatbot with AIML

In AIML (v2.0), here’s how you might define your greeting chatbot from chapter 1.[28]

28

“AI Chat Bot in Python with AIML,” by NanoDano Aug 2015, https://www.devdungeon.com/content/ai-chat-bot-python-aiml#what-is-aiml.

Listing 12.1. nlpia/book/examples/greeting.v2.aiml
<?xml version="1.0" encoding="UTF-8"?><aiml version="2.0">
<category>
    <pattern>HI</pattern>
<template>Hi!</template>
</category>
<category>
    <pattern>[HELLO HI YO YOH YO'] [ROSA ROSE CHATTY CHATBOT BOT CHATTERBOT]<
     /pattern>
    <template>Hi , How are you?</template>
</category>
<category>
    <pattern>[HELLO HI YO YOH YO' 'SUP SUP OK HEY] [HAL YOU U YALL Y'ALL YOUS
      YOUSE]</pattern>
    <template>Good one.</template>
</category>
</aiml>

We used some of the new features of AIML 2.0 (by Bot Libre) to make the XML a little more compact and readable. The square brackets allow you to define alternative spellings of the same word in one line.

Unfortunately, the Python interpreters for AIML (PyAiml, aiml, and aiml_bot) don’t support version 2 of the AIML spec. The Python 3 AIML interpreter that works with the original AIML 1.0 specification is aiml_bot. In aiml_bot, the parser is embedded within a Bot() class, designed to hold the “brain” in RAM that helps a chatbot respond quickly. The brain, or kernel, contains all the AIML patterns and templates in a single data structure, similar to a Python dictionary, mapping patterns to response templates.

AIML 1.0

AIML is a declarative language built on the XML standard, which limits the programming constructs and data structures you can use in your bot. But don’t think of your AIML chatbot as being a complete system. You’ll augment the AIML chatbot with all the other tools you learned about earlier.

One limitation of AIML is the kinds of patterns you can match and respond to. An AIML kernel (pattern matcher) only responds when input text matches a pattern hardcoded by a developer. One nice thing is that AIML patterns can include wild cards, symbols that match any sequence of words. But the words that you do include in your pattern must match precisely. No fuzzy matches, emoticons, internal punctuation characters, typos, or misspellings can be matched automatically. In AIML, you have to manually define synonyms with an </srai>, one at a time. Think of all the stemming and lemmatization you did programmatically in chapter 2. That would be tedious to implement in AIML. Though we show you how to implement synonym and typo matchers in AIML here, the hybrid chatbot you build at the end of the chapter will sidestep this tedium by processing all text coming into your chatbot.

Another fundamental limitation of an AIML <pattern> you need to be aware of is that it can only have a single wild card character. A more expressive pattern-matching language such as regular expressions can give you more power to create interesting chatbots.[29] For now, with AIML, we only use patterns such as “HELLO ROSA *” to match input text such as “Hello Rosa, you wonderful chatbot!”

29

Note

The readability of a language is critical to your productivity as a developer. A good language can make a huge difference, whether you’re building a chatbot or a web app.

We don’t spend too much time helping you understand and write AIML. But we want you to be able to import and customize some of the available (and free) open source AIML scripts out there.[30] You can use AIML scripts, as-is, to give some basic functionality for your chatbot, with little upfront work.

30

Google for “AIML 1.0 files” or “AIML brain dumps” and check out AIML resources such as Chatterbots and Pandorabots: http://www.chatterbotcollection.com/category_contents.php?id_cat=20.

In the next section, we show you how to create and load an AIML file into your chatbot and generate responses with it.

Python AIML interpreter

Let’s build up that complicated AIML script from listing 12.1 one step at a time, and show you how to load and run it within a Python program. The following listing is a simple AIML file that can recognize two sequences of words: “Hello Rosa” and “Hello Troll,” and your chatbot will respond to each differently, like in earlier chapters.

Listing 12.2. nlpia/nlpia/data/greeting_step1.aiml
<?xml version="1.0" encoding="UTF-8"?><aiml version="1.0.1">
 
<category>
    <pattern>HELLO ROSA </pattern>
    <template>Hi Human!</template>
</category>
<category>
    <pattern>HELLO TROLL </pattern>
    <template>Good one, human.</template>
</category>

</aiml>
Note

In AIML 1.0, all patterns must be specified in ALL CAPS.

You’ve set your bot up to respond differently to two different kinds of greetings: polite and impolite. Now let’s use the aiml_bot package to interpret AIML 1.0 files in Python. If you’ve installed the nlpia package, you can load these examples from there using the code in the following listing. If you want to experiment with the AIML files you typed up yourself, you’ll need to adjust the path learn=path to point to your file.

Listing 12.3. nlpia/book/examples/ch12.py
>>> import os
>>> from nlpia.constants import DATA_PATH
>>> import aiml_bot

>>> bot = aiml_bot.Bot(
...     learn=os.path.join(DATA_PATH, 'greeting_step1.aiml'))
Loading /Users/hobs/src/nlpia/nlpia/data/greeting_step1.aiml...
done (0.00 seconds)
>>> bot.respond("Hello Rosa,")
'Hi there!'
>>> bot.respond("hello !!!troll!!!")
'Good one, human.'

That looks good. The AIML specification cleverly ignores punctuation and capitalization when looking for pattern matches.

But the AIML 1.0 specification only normalizes your patterns for punctuation and whitespace between words, not within words. It can’t handle synonyms, spelling errors, hyphenated words, or compound words. See the following listing.

Listing 12.4. nlpia/nlpia/book/examples/ch12.py
>>> bot.respond("Helo Rosa")
WARNING: No match found for input: Helo Rosa
''
>>> bot.respond("Hello Ro-sa")
WARNING: No match found for input: Hello Ro-sa
''

You can fix most mismatches like this using the <srai> tag and a star (*) symbol in your template to link multiple patterns back to the same response template. Think of these as synonyms for the word “Hello,” even though they might be misspellings or completely different words. See the following listing.

Listing 12.5. nlpia/data/greeting_step2.aiml
<category><pattern>HELO *        </pattern><template><srai>HELLO <star/>
</srai></template></category>
<category><pattern>HI *          </pattern><template><srai>HELLO <star/>
</srai></template></category>
<category><pattern>HIYA *        </pattern><template><srai>HELLO <star/>
</srai></template></category>
<category><pattern>HYA *         </pattern><template><srai>HELLO <star/>
</srai></template></category>
<category><pattern>HY *          </pattern><template><srai>HELLO <star/>
</srai></template></category>
<category><pattern>HEY *         </pattern><template><srai>HELLO <star/>
</srai></template></category>
<category><pattern>WHATS UP *    </pattern><template><srai>HELLO <star/>
</srai></template></category>
<category><pattern>WHAT IS UP *  </pattern><template><srai>HELLO <star/>
</srai></template></category>
Note

If you are writing your own AIML files, don’t forget to include the <aiml> tags at the beginning and end. We omitted them in example AIML code here to keep things brief.

Once you load that additional AIML, your bot can recognize a few different ways of saying and misspelling “Hello,” as shown in the following listing.

Listing 12.6. nlpia/nlpia/book/examples/ch12.py
>>> bot.learn(os.path.join(DATA_PATH, 'greeting_step2.aiml'))
>>> bot.respond("Hey Rosa")
'Hi there!'
>>> bot.respond("Hi Rosa")
'Hi there!'
>>> bot.respond("Helo Rosa")
'Hi there!'
>>> bot.respond("hello **troll** !!!") 
 'Good one, human.'

In AIML 2.0, you can specify alternative random response templates with square-bracketed lists. In AIML 1.0 you use the <li> tag to do that. The <li> tag works only within a <condition> or <random> tag. You’ll use a <random> tag to help your bot be a little more creative in how it responds to greetings. See the following listing.

Listing 12.7. nlpia/nlpia/data/greeting_step3.aiml
<category><pattern>HELLO ROSA </pattern><template>
    <random>
        <li>Hi Human!</li>
        <li>Hello friend</li>
        <li>Hi pal</li>
        <li>Hi!</li>
        <li>Hello!</li>
                <li>Hello to you too!</li>
        <li>Greetings Earthling ;)</li>
        <li>Hey you :)</li>
        <li>Hey you!</li>
    </random></template>
</category>
<category><pattern>HELLO TROLL </pattern><template>
    <random>
        <li>Good one, Human.</li>
        <li>Good one.</li>
        <li>Nice one, Human.</li>
        <li>Nice one.</li>
        <li>Clever.</li>
        <li>:)</li>
    </random></template>
</category>

Now your chatbot doesn’t sound nearly as mechanical (at least at the beginning of a conversation). See the following listing.

Listing 12.8. nlpia/nlpia/book/examples/ch12.py
>>> bot.learn(os.path.join(DATA_PATH, 'greeting_step3.aiml'))
>>> bot.respond("Hey Rosa")
'Hello friend'
>>> bot.respond("Hey Rosa")
'Hey you :)'
>>> bot.respond("Hey Rosa")
'Hi Human!'
Note

You likely didn’t get the same responses in the same order that we did when we ran this code. That’s the point of the <random> tag. It’ll choose a random response from the list each time the pattern is matched. There’s no way to set a random seed within aiml_bot, but this would help with testing (pull request anyone?).

You can define synonyms for your own alternative spellings of “Hi” and “Rosa” in separate <category> tags. You could define different groups of synonyms for your templates and separate lists of responses depending on the kind of greeting. For example, you could define patterns for greetings such as “SUP” and “WUSSUP BRO,” and then respond in a similar dialect or similar level of familiarity and informality.

AIML even has tags for capturing strings into named variables (similar to named groups in a regular expression). States in AIML are called topics. And AIML defines ways of defining conditionals using any of the variables you’ve defined in your AIML file. Try them out if you’re having fun with AIML. It’s a great exercise in understanding how grammars and pattern-matching chatbots work. But we’re going to move on to more expressive languages such as regular expressions and Python to build your chatbot. This will allow you to use more of the tools you learned in earlier chapters, such as stemmers and lemmatizers, to handle synonyms and misspellings (see chapter 2). If you use AIML in your chatbot, and you have preprocessing stages such as lemmatization or stemming, you’ll probably need to modify your AIML templates to catch these stems and lemmas.

If you think AIML seems a bit complicated for what it does, you’re not alone. Amazon Lex uses a simplified version of AIML that can be exported to and imported from a JSON file. The startup API.ai developed a dialog specification that was so intuitive that Google bought them out, integrated it with Google Cloud Services, and renamed it Dialogflow. Dialogflow specifications can also be exported to JSON and imported from JSON, but these files aren’t compatible with AIML or Amazon Lex format.

If you think all these incompatible APIs should be consolidated into a single open specification such as AIML, you might want to contribute to the aichat project and the AIRS (AI Response Specification) language development. Aira and the Do More Foundation are supporting AIRS to make it easier for our users to share their content (dialog for interactive fiction, inspiration, training courses, virtual tours, and so on) with each other. The aichat application is a reference implementation of the AIRS interpreter in Python, with a web UX.

Here’s what a typical AIRS specification looks like. It defines the four pieces of information that the chatbot needs to react to a user command in a single row of a flat table. This table can be exported/imported to/from CSV or JSON or a plain Python list of lists:

>>> airas_spec = [
...     ["Hi {name}","Hi {username} how are you?","ROOT","GREETING"],
...     ["What is your name?",
...      "Hi {username} how are you?","ROOT","GREETING"],
...     ]

The first column in an AIRS specification defines the pattern and any parameters you want to extract from the user utterance or text message. The second column defines the response you want the chatbot to say (or text), usually in the form of a template that can be populated with variables from the data context for the chatbot. And it can also contain special keywords to trigger bot actions other than just saying something.

The last two columns are used to maintain the state or context of the chatbot. Whenever the chatbot is triggered by a pattern match, it can transition to a new state if it wants to have different behavior within that state to, say, follow up with additional questions or information. So the two columns at the end of a row just tell the chatbot what state it should be listening for these patterns in and which state it should transition to after it has accomplished the utterance or action specified in the template. These source and destination state names define a graph, like in figure 12.2, that governs the chatbot behavior.

Google’s Dialogflow and Amazon’s Lex are more scalable versions of aichat’s pattern-matching chatbot specification approach. But for many use cases they seem more complicated than they need to be. The open source project aichat (http://github.com/totalgood/aichat) is attempting to provide a more intuitive way to design, visualize, and test chatbots. Check out the aichat or the hybrid chatbot in nlpia (http://github.com/totalgood/nlpia) if you want to learn more about this pattern-matching approach to chatbots. And if you want to implement a large-scale chatbot using this approach for a production application, Google’s Dialogflow (formerly app.ai) and Amazon’s Lex frameworks have extensive documentation on examples you can build on. Though both systems make it possible to deploy a free chatbot within these systems, you’ll quickly get locked into their way of doing things, so you may be better off helping us build aichat.

12.2.2. A network view of pattern matching

As Aira built out its chatbot for assisting those with blindness, we developed some visualization tools to analyze and design that user experience. A network view of the connections between states and the patterns that create those connections revealed opportunities for new patterns and states. A network view allowed us to “run” the dialog in our heads, like running a few lines of Python in your head. And the network view let us navigate the maze of the dialog tree (actually a network or graph) from a birds-eye view, to avoid dialog dead ends and loops.

If you think about it, the patterns and responses of a pattern-matching chatbot define a network (graph). Nodes in this network represent the states. Edges in the network represent the pattern matching triggers that cause the chatbot to say something before transitioning to the next state (node). If you draw the state transitions for a few AIRS patterns and responses you might get something like in figure 12.2.

Figure 12.2. Managing state (context)

This can help you discover dead ends or loops in your dialog that you may want to address by refining or adding patterns to your dialog specification. Aira is working on visualization tools to turn AIRS specs into these graph diagrams (see figure 12.2) with the aichat project (http://github.com/aira/aichat). If Javascript and D3 is your thing, they could use your help.

Now it’s time to learn about another chatbot approach: grounding.

12.3. Grounding

A.L.I.C.E. and other AIML chatbots rely entirely on pattern-matching. And the first popular chatbot, ELIZA, used pattern-matching and templates as well, before AIML was even conceived. But these chatbot developers hardcoded the logic of the responses in patterns and templates. Hardcoding doesn’t “scale” well, not in the processing performance sense, but in the human effort sense. The sophistication of a chatbot built this way grows linearly with the human effort put into it. In fact, as the complexity of this chatbot grows, you begin to see diminishing returns on your effort, because the interactions between all the “moving parts” grow and the chatbot behavior becomes harder and harder to predict and debug.

Data-driven programming is the modern approach to most complex programming challenges these days. How can you use data to program your chatbot? In the last chapter, you learned how to create structured knowledge from natural language text (unstructured data) using information extraction. You can build up a network of relationships or facts just based on reading text, such as Wikipedia, or even your own personal journal. In this section, you’ll learn how to incorporate this knowledge about the world (or your life) into your chatbot’s bag of tricks. This network of logical relationships between things is a knowledge graph or knowledge base that can drive your chatbot’s responses.

This knowledge graph can be processed with logical inference to answer questions about the world of knowledge contained in the knowledge base. The logical answers can then be used to fill in variables within templated responses to create natural language answers. Question answering systems, such as IBM’s Jeopardy-winning Watson, were originally built this way, though more recent versions almost surely also employ search or information retrieval technology. A knowledge graph is said to “ground” the chatbot to the real world.

This knowledge-base approach isn’t limited to answering questions just about the world. Your knowledge base can also be populated in real time with facts about an ongoing dialog. This can keep your chatbot up-to-speed on who your conversation partner is, and what they’re like.

If you take this knowledge modeling one step deeper, you can build subgraphs of knowledge about what the chatbot’s dialog partners believe about the world. If you’re familiar with database design you can think of this as a partial mirror of external databases—knowledge bases in this case. This can be a temporary “cache” of only the most recent knowledge, or it can be a permanent rolling log of all the knowledge your chatbot has learned (and unlearned) about the other dialog participants. Each statement by dialog participants can be used to populate a “theory of mind,” a knowledge base about what each speaker believes about the world. This could be as simple as building patterns to extract the nicknames that dialog participants use when addressing each other or the chatbot, like we did in chapter 1.

If you think about it, humans seem to participate in dialog in a more sophisticated way than merely regurgitating canned responses, such as the AIML chatbot you just built. Your human brain enables you to think about the logic of what your conversation partner said and attempt to infer something from what you remember about real-world logic and each other. You may have to make several inferences and assumptions to understand and respond to a single statement. So this addition of logic and grounding to your chatbot may make it be more human-like, or at least more logical.

This grounding approach to chatbots works well for question answering chatbots, when the knowledge required to answer the question is within some broad knowledge base that you can obtain from an open source database. Some examples of open knowledge bases you can use to ground your chatbot include

So all you need is a way to query the knowledge base to extract the facts you need to populate a response to a user’s statement. And if the user is asking a factual question that your database might contain, you could translate their natural language question (such as “Who are you?” or “What is the 50th state of the United States?”) into a knowledge base query to directly retrieve the answer they’re looking for. This is what Google search does using Freebase and other knowledge bases they combined together to create their knowledge graph.

You could use your word pattern matching skills from chapter 11 to extract the critical parts of a question from the user’s statement, such as the named entities or the relationship information sought by the question. You’d check for key question words such as “who,” “what,” “when,” “where,” “why,” and “is” at the beginning of a sentence to classify the type of question. This would help your chatbot determine the kind of knowledge (node or named entity type) to retrieve from your knowledge graph.

Quepy[36] is a natural language query compiler that can produce knowledge base and database queries using these techniques. The SQL-equivalent for a knowledge graph of RDF triples is called SPARQL.[37]

36

See the web page titled “Welcome to Quepy’s documentation! — Quepy 0.1 documentation” (http://quepy.readthedocs.io/en/latest/).

37

See the web page titled “SPARQL Query Language for RDF” (https://www.w3.org/TR/rdf-sparql-query/).

12.4 Retrieval (search)

Another more data-driven approach to “listening” to your user is to search for previous statements in your logs of previous conversations. This is analogous to a human listener trying to recall where they’ve heard a question or statement or word before. A bot can search not only its own conversation logs, but also any transcript of human-to-human conversations, bot-to-human conversations, or even bot-to-bot conversations. But, as usual, garbage in means garbage out. So you should clean and curate your database of previous conversations to ensure that your bot is searching (and mimicking) high-quality dialog. You would like humans to enjoy the conversation with your bot.

A search-based chatbot should ensure that its dialog database contains conversations that were enjoyable or useful. And they should probably be on some theme that the bot personality is expected to converse in. Some examples of good sources of dialog for a search-based bot include movie dialog scripts, customer service logs on IRC channels (where the users were satisfied with the outcome), and direct-message interactions between humans (when those humans are willing to share them with you). Don’t do this on your own email or SMS message logs without getting the written agreement of all humans involved in the conversations you want to use.

If you decide to incorporate bot dialog into your corpus, be careful. You only want statements in your database that have had at least one human appear to be satisfied with the interaction, if only by continuing the conversation. And bot-to-bot dialog should rarely be used, unless you have access to a really smart chatbot.

Your search-based chatbot can use a log of past conversations to find examples of statements similar to what the bot’s conversation partner just said. To facilitate this search, the dialog corpus should be organized in statement-response pairs. If a response is responded to then it should appear twice in your database, once as the response and then again as the statement that is prompting a response. The response column in your database table can then be used as the basis for your bot’s response to the statements in the “statements” (or prompt) column.

12.4.1. The context challenge

The simplest approach is to reuse the response verbatim, without any adjustment. This is often an OK approach if the statement is a good semantic (meaning) match for the statement your bot is responding to. But even if all the statements your users ever made could be found in your database, your bot would take on the personality of all the humans that uttered the responses in your dialog database. This can be a good thing, if you have a consistent set of responses by a variety of humans. But it can be a problem if the statement you are trying to reply to is dependent on the longer-term context of a conversation or some real-world situation that has changed since your dialog corpus was assembled.

For example, what if someone asked your chatbot “What time is it?” Your chatbot shouldn’t reuse the reply of the human who replied to the best-matched statement in your database. That would work only if the question’s time corresponded to the time the matching dialog statement was recorded. This time information is called context, or state, and should be recorded and matched along with the statement’s natural language text. This is especially important when the statement’s semantics point to some evolving state that is recorded in your context, or the chatbot’s knowledge base.

Some other examples of how real-world knowledge or context should influence a chatbot’s reply are the questions “Who are you?” or “Where are you from?” The context in this case is the identity and background of the person being addressed by the question. Fortunately, this is context that you can generate and store quite easily in a knowledge base or database containing facts about the profile or back-story for your bot. You’d want to craft your chatbot profile to include information such as a persona that roughly reflects the average or median profile of the humans who made the statements in your database. To compute this, you can use the profiles of the users that made statements in your dialog database.

Your chatbot’s personality profile information could be used to resolve “ties” in the search for matching statements in your database. And if you want to be super sophisticated, you can boost the rank of search results for replies from humans that are similar to your bot persona. For example, imagine you know the gender of the people whose statements and responses you recorded in your dialog database. You’d include the nominal gender of the chatbot as another “word” or dimension or database field you’re searching for among the genders of the respondents in your database. If this respondent gender dimension matched your chatbot’s gender, and the prompting statement words or semantic vector were a close match for the corresponding vector from your user’s statement, that would be a great match at the top of your search results. The best way to do this matching is to compute a scoring function each time a reply is retrieved and include in this score some profile match information.

Alternatively, you could solve this context challenge by building up a background profile for your bot and storing it in a knowledge base manually. You’d just make sure to only include replies in your chatbot’s database that matched this profile.

No matter how you use this profile to give your chatbot a consistent personality, you’ll need to deal with questions about that personality profile as special cases. You need to use one of the other chatbot techniques rather than retrieval if your database of statements and replies doesn’t contain a lot of answers to questions such as “Who are you?” “Where are you from?” and “What’s your favorite color?” If you don’t have a lot of profile statement-reply pairs, you’d need to detect any questions about the bot and use a knowledge base to “infer” an appropriate answer for that element of the statement. Alternatively, you could use the grammar-based approach to populate a templated response, using information retrieved from a structured dataset for the chatbot profile.

To incorporate state or context into a retrieval-based chatbot, you can do something similar to what you did for the pattern-matching chatbot. If you think about it, listing a bunch of user statements is just another way of specifying a pattern. In fact, that’s exactly the approach that Amazon Lex and Google Dialogflow take. Rather than defining a rigid pattern to capture the user command, you can just provide the dialog engine with a few examples. So just as you associated a state with each pattern in your pattern-matching chatbot, you just need to tag your statement-response example pairs with a named state as well.

This tagging can be difficult if your example state-response pairs are from an unstructured, unfiltered data source such as the Ubuntu Dialog Corpus or Reddit. But with dialog training sets such as Reddit, you can often find some small portions of the massive dataset that can be automatically labeled based on their channel and reply thread. You can use the tools of semantic search and pattern matching to cluster the initial comment that preceded a particular thread or discussion. And these clusters can then become your states. Detecting transitions from one topic or state to another can be difficult, however. And the states that you can produce this way aren’t nearly as precise and accurate as those you can generate by hand.

This approach to state (context) management can be a viable option, if your bot just needs to be entertaining and conversational. But if you need your chatbot to have predictable and reliable behaviors, you probably want to stick to the pattern-matching approach or hand-craft your state transitions.

12.4.2. Example retrieval-based chatbot

You’re going to be following along with the ODSC 2017 tutorial on building a retrieval-based chatbot. If you want to view the video or the original notebook for this tutorial, check out the github repository for it at https://github.com/totalgood/prosocial-chatbot.

Our chatbot is going to use the Ubuntu Dialog Corpus, a set of statements and replies recorded on the Ubuntu IRC channel, where humans are helping each other solve technical problems. It contains more than seven million utterances and more than one million dialog sessions, each with multiple turns and many utterances.[38] This large number of statement-response pairs makes it a popular dataset that researchers use to check the accuracy of their retrieval-based chatbots.

38

“The Ubuntu Dialogue Corpus: A Large Dataset for Research in Unstructured Multi-Turn Dialogue Systems” by Lowe et al., 2015 https://arxiv.org/abs/1506.08909.

These are the sort of statement-response pairings you need to “train” a retrieval-based chatbot. But don’t worry, you’re not going to use all seven million utterances. You’ll just use about 150 thousand turns and see if that’s enough to give your chatbot the answers to some common Ubuntu questions. To get started, download the bitesized Ubuntu corpus shown in the following listing.

Listing 12.9. ch12_retrieval.py
>>> from nlpia.data.loaders import get_data
>>> df = get_data('ubuntu_dialog')
Downloading ubuntu_dialog
requesting URL:
https://www.dropbox.com/s/krvi79fbsryytc2/ubuntu_dialog.csv.gz?dl=1
remote size: 296098788
Downloading to /Users/hobs/src/nlpia/nlpia/bigdata/ubuntu_dialog.csv.gz
39421it [00:39, 998.09it/s]

You may get warning messages about the /bigdata/ path not existing if you haven’t used nlpia.data.loaders.get_data() on a big dataset yet. But the downloader will create one for you when you run it for the first time.

Note

The scripts here will work if you have 8 GB of free RAM to work with. If you run out of memory, try reducing the dataset size—slice out a smaller number of rows in df. In the next chapter, we use gensim to process data in batches “out of core” so that you can work with larger datasets.

What this corpus looks like can be seen in the following listing.

Listing 12.10. ch12_retrieval.py
>>> df.head(4)
                        Context                                Utterance
0  i think we could import the old comments via r...   basically each xfree86
       upload will NOT force u...
1  I'm not suggesting all -
       only the ones you mod...                         oh? oops. __eou__
2  afternoon all __eou__ not entirely related to ...    we'll have a BOF about
      this __eou__ so you're ...
3  interesting __eou__ grub-install worked with /
     ...   i fully endorse this suggestion </quimby> __eo...

Notice the “__eou__” tokens? This looks like it might be a pretty challenging dataset to work with. But it’ll give you practice with some common preprocessing challenges in NLP. Those tokens mark the “end of utterance,” the point at which the “speaker” hit [RETURN] or [Send] on their IRC client. If you print out some example Context fields, you’ll notice that there are also “__eot__” (“end of turn”) markers to indicate when someone concluded their thought and was waiting for a reply.

But if you look inside a context document (row in the table), you’ll see there are multiple “__eot__” (turn) markers. These markers help more sophisticated chatbots test how they handle the context problem we talked about in the previous section. But you’re going to ignore the extra turns in the corpus and focus only on the last one, the one that the utterance was a reply to. First, let’s create a function to split on those “__eot__” symbols and clean up those “__eou__” markers, as seen in the following listing.

Listing 12.11. ch12_retrieval.py
>>> import re
>>> def split_turns(s, splitter=re.compile('__eot__')):
...    for utterance in splitter.split(s):
...        utterance = utterance.replace('__eou__', '
')
...        utterance = utterance.replace('__eot__', '').strip()
...        if len(utterance):
...            yield utterance

Let’s run that split_turns function on a few rows in the DataFrame to see if it makes sense. You’ll retrieve only the last turn from both the context and the utterance and see if that’ll be enough to train a retrieval-based chatbot. See the following listing.

Listing 12.12. ch12_retrieval.py
>>> for i, record in df.head(3).iterrows():
...     statement = list(split_turns(record.Context))[-1]
...     reply = list(split_turns(record.Utterance))[-1]
...     print('Statement: {}'.format(statement))
...     print()
...     print('Reply: {}'.format(reply))

This should print out something like this:

Statement: I would prefer to avoid it at this stage. this is something that
     has gone into XSF svn, I assume?
Reply:  each xfree86 upload will NOT force users to upgrade 100Mb of fonts
     for nothing
 no something i did in my spare time.
 
Statement: ok, it sounds like you're agreeing with me, then
 though rather than "the ones we modify", my idea is "the ones we need to
     merge"
Reply: oh? oops.

Statement: should g2 in ubuntu do the magic dont-focus-window tricks?
 join the gang, get an x-series thinkpad
 sj has hung on my box, again.
 what is monday mornings discussion actually about?
Reply: we'll have a BOF about this
 so you're coming tomorrow ?

Excellent! It looks like it has statements and replies that contain multiple statements (utterances). So your script is doing what you want, and you can use it to populate a statement-response mapping table, as shown in the following listing.

Listing 12.13. ch12_retrieval.py
>>> from tqdm import tqdm

>>> def preprocess_ubuntu_corpus(df):
...     """
...     Split all strings in df.Context and df.Utterance on
...     __eot__ (turn) markers
...     """
...     statements = []
...     replies = []
...     for i, record in tqdm(df.iterrows()):
...         turns = list(split_turns(record.Context))
...         statement = turns[-1] if len(turns) else '
'      1
...         statements.append(statement)
...         turns = list(split_turns(record.Utterance))
...         reply = turns[-1] if len(turns) else '
'
...         replies.append(reply)
...     df['statement'] = statements
...     df['reply'] = replies
...     return df

  • 1 You need an if because some of the statements and replies contained only whitespace.

Now you need to retrieve the closest match to a user statement in the statement column, and reply with the corresponding reply from the reply column. Do you remember how you found similar natural language documents using word frequency vectors and TF-IDF vectors in chapter 3? See the following listing.

Listing 12.14. ch12_retrieval.py
>>> from sklearn.feature_extraction.text import TfidfVectorizer
>>> df = preprocess_ubuntu_corpus(df)
>>> tfidf = TfidfVectorizer(min_df=8, max_df=.3, max_features=50000)
>>> tfidf.fit(df.statement)                                           1

  • 1 Notice you only need to compute the statement (not reply) TF-IDFs, because those are the things you want to search.

Let’s create a DataFrame called X to hold all these TF-IDF vectors for each of the 150 thousand statements, as shown in the following listing.

Listing 12.15. ch12_retrieval.py
>>> X = tfidf.transform(df.statement)
>>> X = pd.DataFrame(X.todense(), columns=tfidf.get_feature_names())

One way to find the closest statement is to compute the cosine distance from the query statement to all the statements in your X matrix, as shown in the following listing.

Listing 12.16. ch12_retrieval.py
>>> x = tfidf.transform(['This is an example statement that
...     we want to retrieve the best reply for.'])
>>> cosine_similarities = x.dot(X.T)
>>> reply = df.loc[cosine_similarities.argmax()]

That took a long time (more than a minute on my MacBook). And you didn’t even compute a confidence value or get a list of possible replies that you might be able to combine with other metrics.

12.4.3. A search-based chatbot

What if the patterns you wanted to match were the exact things people have said in previous conversations? That’s what a search-based chatbot (or retrieval-based chatbot) does. A search-based chatbot indexes a dialog corpus so that it can easily retrieve previous statements similar to the one it’s being asked to reply to. It can then reply with one of the replies associated with that statement in the corpus that it has “memorized” and indexed for quick retrieval.

If you’d like to quickly get going with a search-based chatbot, ChatterBot by Gunther Cox is a pretty good framework to cut your teeth on. It’s easy to install (just pip install ChatterBot), and it comes with several conversation corpora that you can use to “train” your chatbot to carry on basic conversations. ChatterBot has corpora that allow it to talk about things such as sports trivia, wax philosophical about AI sentience, or just shoot the breeze with small talk. ChatterBot can be “trained” on any conversation sequence (dialog corpus). Don’t think of this as machine learning training, but rather just indexing a set of documents for search.

By default ChatterBot will use both humans’ statements as material for its own statements during training. If you want to be more precise with the personality of your chatbot, you’ll need to create your own corpus in the ChatterBot “.yml” format. To ensure that only one personality is mimicked by your bot, make sure your corpus contains conversations of only two statements each, one prompt and one reply; the reply being from the personality you want to imitate. Incidentally, this format is similar to the AIML format, which has a pattern (the prompting statement in ChatterBot) and a template (the response in ChatterBot).

Of course, a search-based chatbot built this way is quite limited. It’s never going to come up with new statements. And the more data you have, the harder it is to brute force the search of all the previous statements. So the smarter and more refined your bot is, the slower it’ll be. This architecture doesn’t scale well. Nonetheless, we show you some advanced techniques for scaling any search or index-based chatbot with indexing tools such as locality sensitive hashes (pip install lshash3) and approximate near neighbors (pip install annoy).

Out of the box, ChatterBot uses SQLite as its database, which highlights these scaling issues as soon as you exceed about 10k statements in your corpus. If you try to train a SQLite-based ChatterBot on the Ubuntu Dialog Corpus you’ll be waiting around for days... literally. It took me more than a day on a MacBook to ingest only 100k statement-response pairs. Nonetheless, this ChatterBot code is quite useful for downloading and processing this motherlode of technical dialog about Ubuntu. ChatterBot takes care of all the bookkeeping for you, downloading and decompressing the tarball automatically before walking the “leafy” file system tree to retrieve each conversation.

How ChatterBot’s “training” data (actually just a dialog corpus) is stored in a relational database is shown in the following listing.

Listing 12.17. ch12_chatterbot.sql
sqlite> .tables
conversation              response                  tag
conversation_association  statement                 tag_association
sqlite> .width 5 25 10 5 40
sqlite> .mode columns
sqlite> .mode column
sqlite> .headers on
sqlite> SELECT id, text, occur FROM response LIMIT 9;
id     text                 occur  statement_text
-----  -------------------  -----  ----------------------------------------
1      What is AI?          2      Artificial Intelligence is the branch of
2      What is AI?          2      AI is the field of science which concern
3      Are you sentient?    2      Sort of.
4      Are you sentient?    2      By the strictest dictionary definition o
5      Are you sentient?    2      Even though I'm a construct I do have a
6      Are you sapient?     2      In all probability, I am not. I'm not t
7      Are you sapient?     2      Do you think I am?
8      Are you sapient?     2      How would you feel about me if I told yo
9      Are you sapient?     24     No.

Notice that some statements have many different replies associated with them, which allows the chatbot to choose among the possible replies based on mood, context, or random chance. ChatterBot just chooses a response at random, but yours could be more sophisticated if you incorporate some other objective or loss function or heuristic to influence the choice. Also, notice that the created_at dates are all the same. That happens to be the date when we ran the ChatterBot “training” script, which downloaded the dialog corpora and loaded them into the database.

Search-based chatbots can also be improved by reducing the statement strings down to topic vectors of fixed dimensionality, using something such as Word2vec (summing all the word vectors for a short statement), or Doc2vec (chapter 6) or LSA (chapter 4). Dimension reduction will help your bot generalize from the examples you train it with. This helps it respond appropriately when the meaning of the query statement (the most recent statement by your bot’s conversation partner) is similar in meaning to one of your corpus statements, even if it uses different words. This will work even if the spelling or characters in statements are very different. Essentially, this semantic search-based chatbot is automating the programming of the templates you programmed in AIML earlier in this chapter. This dimension reduction also makes search-based chatbots smarter using machine learning (data-driven) than would be possible with a hardcoded approach to machine intelligence. Machine learning is preferable to hardcoding whenever you have a lot of labeled data, and not a lot of time (to code up intricate logic and patterns to trigger responses). For search-based chatbots, the only “label” needed is an example response for each example statement in the dialog.

12.5. Generative models

We promised a generative model in this chapter. But if you recall the sequence-to-sequence models you built in chapter 10, you may recognize them as generative chatbots. They’re machine learning translation algorithms that “translate” statements by your user into replies by your chatbot. So we don’t go into generative models in any more detail here, but know that many more kinds of generative models are out there. If you want to build a creative chatbot that says things that have never been said before, generative models such as these may be what you need:

We talked about attention networks (enhanced LSTMs) in chapter 10, and we showed the kinds of novel statements your chatbot can spontaneously generate. In the next section, we take that approach in another direction.

12.5.1. Chat about NLPIA

Finally, the moment you’ve been waiting for... a chatbot that can help write a book about NLP. We’ve finally written (and you’ve read) enough text for the chatbot to have some seed material to work with. In this section, we show you how to use transfer learning to build a generative NLP pipeline to produce some of the sentences you may have already skimmed right by without noticing.

Why transfer learning? In addition to some seed text about the specific topic you want your chatbot to understand, generative models need an even bigger corpus of more general text to learn a language model from. Your chatbot needs to be able to do a lot of reading before it can recognize all the ways words are put together to form grammatically correct and meaningful sentences. And that corpus has to be segmented into grammatically correct sentences. So the project Gutenberg corpus isn’t the ideal place for this model.

Think of how many books you had to read as a child before you built a decent vocabulary and a sense for the correct way to put words together into sentences. And your teachers probably gave you a lot of clues, like context, while you were practicing that reading.[42] Plus, humans are much better than machines at learning.[43]

42

“On the role of context in first- and second-language vocabulary learning” (https://www.ideals.illinois.edu/bitstream/handle/2142/31277/TR-627.pdf).

43

See “One-shot and Few-shot Learning of Word Embeddings” (https://openreview.net/pdf?id=rkYgAJWCZ) and “One-shot learning by inverting a compositional causal process” (http://www.cs.toronto.edu/~rsalakhu/papers/lake_nips2013.pdf).

This data-intensive language model learning is a particularly big challenge for character-based models. In character sequence language models, your chatbot needs to learn how to put characters together to form properly spelled and meaningful words, in addition to learning how to put those new words together to make sentences. So you’ll want to reuse an existing language model trained on a large body of text in the language and style you’d like to imitate with your bot. If you think about this for a moment, you can probably see why data limitations have limited how far current NLP researchers have been able to climb up the complexity curve from characters to words to sentences. Composing paragraphs, chapters, and novels is still an active area of research. So we stop our climb there and show you how to generate a few sentences like those generated for the “about this book” front matter for NLPIA.

The DeepMind folks have provided TensorFlow character sequence-to-sequence language models pretrained on more than 500MB of sentences from CNN and Daily Mail news feeds.[44] And if you want to build your own language model, they’ve provided all the sentences in two large datasets as part of their “reading comprehension” (Q&A) challenge.[45] We reused the pretrained text summarization model directly to generate sentences for the “about this book” NLPIA front matter. You can also use these models to augment your own machine learning pipeline with an approach called “transfer learning,” like we did with word vectors in Chapter 6.

44

Pretrained TensorFlow text summarization model: TextSum from Google Brain (https://github.com/totalgood/pointer-generator#looking-for-pretrained-model) and a paper describing the model https://arxiv.org/abs/1704.04368.

45

The dataset includes reading comprehension questions and answers as well as the sentences from news articles that you need to answer those questions: DeepMind Q&A Dataset (https://cs.nyu.edu/%7Ekcho/DMQA/).

Here’s the algorithm:

  1. Download a pretrained sequence-to-sequence text summarization model (https://github.com/totalgood/pointer-generator#looking-for-pretrained-model).
  2. Parse and segment asciidoc text to extract natural language sentences with nlpia.book_parser (https://github.com/totalgood/nlpia/blob/master/src/nlpia/.py).
  3. Use the text summarization model to summarize the first 30 or so lines of text in each asciidoc file (typically a chapter): https://github.com/totalgood/nlpia/blob/master/src/nlpia/book/examples/ch12_chat_about_nlpia.py.
  4. Filter the generated sentences for novelty to avoid regurgitation of existing sentences from the book: https://github.com/totalgood/nlpia/blob/master/src/nlpia/book_parser.py.

Here are the only two well-formed and marginally original sentences that our @ChattyAboutNLPIA bot came up with. This is @Chatty’s attempt to summarize the first 30 lines of chapter 5:

Convolutional neural nets make an attempt to capture that ordering relationship by capturing localized relationships.

This is @Chatty’s summary of chapter 8:

Language’s true power is not necessarily in the words, but in the intent and emotion that formed that particular combination of words.

These sentences were among the 25 outputs (https://github.com/totalgood/nlpia/blob/master/src/nlpia/data/nlpia_summaries.md) for this hacky pipeline. In the coming months, we’ll modify the pipeline in nlpia.book.examples.ch12_chat_about _nlpia to provide more useful results. One enhancement will be to process the entire book with TextSum so it has more material to work with. We’ll also need to apply some more filtering:

  1. Filter the generated sentences for well-formedness.[46]

    46

    Thank you Kyle Gorman @wellformedness (https://twitter.com/wellformedness) for your 100+ suggestions and bits of clever content for this book. See also https://en.wikipedia.org/wiki/Well-formedness.

  2. Filter generated sentences for your style and sentiment objectives.
  3. Automatically detokenize and unfold case (capitalization), if necessary.

12.5.2. Pros and cons of each approach

Now that you know all about the four major chatbot approaches, can you think how you might combine them to get the best out of your bot? Figure 12.3 lists the advantages and disadvantages of each approach.

Figure 12.3. Advantages and disadvantages of four chatbot approaches

12.6 Four-wheel drive

As we promised at the beginning of this chapter, we now show you how to combine all four approaches to get traction with your users. To do this, you need a modern chatbot framework that’s easy to extend and modify and can efficiently run each of these algorithm types in parallel.[47] You’re going to add a response generator for each of the four approaches using the Python examples from earlier in the chapter. And then you’re going to add the logic to decide what to say by choosing one of the four (or many) responses. You’re going to have your chatbot think before it speaks, say things several different ways to itself first, and rank or merge some of these alternatives to produce a response. And maybe you can even try to be prosocial with your replies by checking their sentiment before “hitting the send button.”

47

We’re building an open source chatbot framework at Aira called aichat to help our users and their friends contribute “content” to our library of dialog to help and entertain people with blindness and low vision: http://github.com/aira/aichat.

12.6.1. The Will to succeed

Will is a modern programmer-friendly chatbot framework by Steven Skoczen that can participate in your HipChat and Slack channels as well as others.[48] Python developers will enjoy the modular architecture. However it’s pretty heavyweight in terms of requirements and installation. Fortunately, it comes with a Dockerized container you can use to spin up your own chatbot server.

48

GitHub Repository: https://github.com/skoczen/will.

Will uses regular expressions to make matches. Python itself can be used for any logical conditions you need to evaluate. And the jinja2 library is used for templating. Each one of these portions of the pipeline add versatility and flexibility to the kinds of behaviors you can build into your chatbot. As a result, Will is much more flexible than AIML-based frameworks. But Will still suffers from the same limitations that hold back all pattern-based chatbots (including AIML)--it can’t learn from data; it must be “taught” by the developer writing code for each and every branch in the logic tree.

Installing Will

The installation documentation for Will has a couple small gaps. By the time this goes to print, we hope to have them fixed, so you can likely just read the high-quality docs.[49] On Mac OS X, you can install and launch a redis server () brew install redis.

49

Will documentation: http://skoczen.github.io/will/.

Hello Will

Heres’s what a conversation with an untrained Will looks like, if you ignore the tracebacks about port 80 permissions, or you can figure out how to avoid these errors:

You:  Hey
Will: hello!
You:  What's up?
Will: I heard you, but I'm not sure what to do.
You:  How are you?
Will: Doing alright. How are you?
You:  What are you?
Will: Hmm. I'm not sure what to say.
You:  Are you a bot?
Will: I didn't understand that.

As you can see, out of the box, Will is polite but doesn’t understand much. You can easily change Will for Rosa (or any other name). And you can use your natural language processing skills to beef up some of his patterns and expand his literary power.

12.7. Design process

To create a useful app, product managers and developers compose user stories. A user story describes a sequence of actions performed by a user in interacting with your app and how your app should respond. These can be imagined based on similar experiences in the real world with similar products, or they can be translated from user feature requests or feedback. Software features are tied to a user story to improve the likelihood that the development effort is focused on something that’ll add usefulness to your product.

User stories for a chatbot can often be composed as statements (text messages) that a user might communicate to the bot. Those user statements are then paired with the appropriate response or action by the chatbot or virtual assistant. For a retrieval-based chatbot, this table of user stories is all that’s required to “train” a chatbot for these particular responses and stories. It’s up to you, the developer, to identify stories that can be generalized so that your design team doesn’t have to specify everything your bot must understand and all the different things it can say. Can you tell which of the four chatbot techniques would be appropriate for each of these questions?

  • “Hello!” => “Hello!”
  • “Hi” => “Hi!”
  • “How are you?” => “I’m fine. How are you?”
  • “How are you?” => “I’m a stateless bot, so I don’t have an emotional state.”
  • “Who won the 2016 World Series?” => “Chicago Cubs”
  • “Who won the 2016 World Series?” => “The Chicago Cubs beat the Cleveland Indians 4 to 3”
  • “What time is it” => “2:55 pm”
  • “When is my next appointment?” => “At 3 pm you have a meeting with the subject 'Springboard call'”
  • “When is my next appointment?” => “At 3 pm you need to help Les with her Data Science course on Springboard”
  • “Who is the President?” => “Sauli Niinistö”
  • “Who is the President?” => “Barack Obama”

Several valid responses may be possible for any given statement, even for the exact same user and context. And it’s also common for multiple different prompting statements to elicit the same exact chatbot response (or set of possible responses). The many-to-many mapping between statements and responses works both ways, just as it does for human dialog. So the number of possible combinations of valid statement => response mappings can be enormous—seemingly infinite (but technically finite).

And you must also expand the combinations of statement-response pairs in your user stories using named variables for context elements that change often:

  • Date
  • Time
  • Location: country, state, county, and city, or latitude and longitude
  • Locale: US or Finland formatting for date, time, currency, and numbers
  • Interface type: mobile or laptop
  • Interface modality: voice or text
  • Previous interactions: whether user asked for details about baseball stats recently
  • Streaming audio, video, and sensor data from a mobile device (Aira.io)

IBM Watson and Amazon Lex chatbot APIs rely on knowledge bases that aren’t easy to evolve quickly and keep up-to-speed with these evolving context variables. The “write rate” for these databases of knowledge are too slow to handle many of these evolving facts about the world that the chatbot and the user are interacting with.

The list of possible user stories for even the simplest of chatbots is technically finite, but it’s quite large for even the simplest real-world chatbot. One way to deal with this explosion of combinations is to combine many user interactions into a single pattern or template. For the statement side of the mapping, this template approach is equivalent to creating a regular expression (or finite state machine) to represent some group of statements that should cause a particular pattern response. For the response side of the mapping, this approach is equivalent to Jinja2 or Django or Python f-string templates.

Thinking back to your first chatbot in chapter 1, we can represent statement => response mappings that map regular expressions for the statement to a Python f-string for the response:

>>> pattern_response = {
...     r"[Hh]ello|[Hh]i[!]*":
...         r"Hello {user_nickname}, would you like to play a game?",
...     r"[Hh]ow[s]*('s|are|'re)?[s]*[Yy]ou([s]*doin['g]?)?":
...         r"I'm {bot_mood}, how are you?",
...     }

But this doesn’t allow for complex logic. And it requires hand coding rather than machine learning. So each mapping doesn’t capture a broad range of statements and responses. You’d like a machine learning model to be able to handle a wide range of sports questions, or help a user manage their calendar.

Important

Don’t change those raw string templates to f-strings with f" or they’ll be rendered at the time of instantiation. Your bot may not know much about the world at the time you create the pattern_response dictionary.

Here are some example chatbot user stories that don’t lend themselves well to the template approach:

  • “Where is my home” => “Your home is 5 minutes away by foot, would you like directions?”
  • “Where am I” => “You are in SW Portland near Goose Hollow Inn” or “You are at 2004 SW Jefferson Street”
  • “Who is the President?” => “Sauli Niinistö” or “Barack Obama” or “What country or company ...”
  • “Who won the 2016 World Series?” => “Chicago Cubs” or “The Chicago Cubs beat the Cleveland Indians 4 to 3”
  • “What time is it” => “2:55 pm” or “2:55 pm, time for your meeting with Joe” or ...

And here are some general IQ test questions that are too specific to warrant a pattern-response pair for each variation. A knowledge base is usually the answer for general intelligence questions. Nonetheless, that’s probably how the Mitsuku chatbot was able to get close to the right answer in a recent test by Byron Reese:

  • “Which is larger, a nickel or a dime?” => “Physically or monetarily?” or “A nickel is physically larger and heavier but less valuable monetarily.”
  • “Which is larger, the Sun or a nickel?” => “The Sun, obviously.”[50]

    50

    Byron Reese, “AI Minute” podcast.

  • “What’s a good strategy at Monopoly?” => “Buy everything you can, and get lucky.”
  • “How should I navigate a corn-row maze?” => “Keep your hand against one wall of corn and follow it until it becomes an outside wall of the maze.”
  • “Where does sea glass come from?” => “Garbage... fortunately the polishing of sand and time can sometimes turn human refuse, like broken bottles, into beautiful gemstones.”

Even though these cannot be easily translated directly into code, they do translate directly into an automated test set for your NLP pipeline. Tests like these can be used to evaluate a new chatbot approach or feature or just to track progress over time.[51] If you can think of some more chatbot IQ questions, add them to the growing list at nlpia/data/iq_test.csv (https://github.com/totalgood/nlpia/blob/master/src/nlpia/data/iq_test.csv). And certainly include them in automated testing of your own chatbot. You never know when your bot is going to surprise you.

51

2017 Andrew Ng lecture to Stanford Business School students: https://youtu.be/21EiKfQYZXc?t=48m6s.

12.8 Trickery

You’ll want to have a few specific tricks up your sleeve when building a chatbot. These tricks will help you ensure that your chatbot doesn’t go off the rails too often.

12.8.1. Ask questions with predictable answers

When asked a question that you don’t know the answer to, the chatbot can respond with a clarifying question. And if this clarifying question is well within the knowledge domain or personality profile of the chatbot, it’s possible to predict the form of the answer that a human would make. Then the chatbot can use the user’s response to regain control of the conversation and steer it back toward topics that it knows something about. To avoid frustration, try to make the clarifying question humorous, or positive and flattering, or in some way pleasing to the user:

Human: "Where were you born?"
 
Sports Bot: "I don't know, but how about those Mets?"
Therapist Bot: "I don't know, but are you close to your mother?"
Ubuntu Assistant Bot: "I don't know, but how do you shut down your Ubuntu PC
     at night?"

You can often use semantic search to find question-answer pairs, jokes, or interesting trivia in the chatbot’s knowledge base that are at least tangentially related to what the user is asking about.

12.8.2. Be entertaining

Sometimes your generative process may take too long to converge to a high-quality message. And your chatbot may not find a reasonable clarifying question to ask. In that situation your chatbot has two choices: 1. admit ignorance, or 2. make up a non sequitur.

A non sequitur is a statement that has nothing to do with what the user asked about. Such statements are generally considered antisocial, and sometimes manipulative. Honesty is the best policy for your prosocial chatbot. And the more open you are, the more likely you are to build trust with your user. Your user might enjoy learning a bit about the “core” of your chatbot if you reveal the size of your database of responses or actions you can handle. You can also share some of the garbled responses that didn’t make it through your grammar and style checker. The more honest you are the more likely the user is to be kind in return and try to help your chatbot get back on track. Cole Howard found that users would often coax his MNIST-trained handwriting recognizer toward the right answer by redrawing the digits in a more clear way.

So for a commercial chatbot, you may want this useless response to be sensational, distracting, flattering, or humorous. And you’ll probably also want to ensure that your responses are randomly selected in a way that a human would consider random. For example, don’t repeat yourself very often.[52] And use varying sentence structure, form, and style over time. That way you can monitor your customers’ responses and measure their sentiment to determine which of your non sequiturs were the least annoying.

52

Humans underestimate the number of repetitions there should be in a random sequence: https://mindmodeling.org/cogsci2014/papers/530/paper530.pdf.

12.8.3. When all else fails, search

If your bot can’t think of anything to say, try acting like a search engine or search bar. Search for webpages or internal database records that might be relevant to any question you might receive. But be sure to ask the user whether the page titles might help the user before spitting out all the information they contain. Stack Overflow, Wikipedia, and Wolfram Alpha are good resources at the ready for many bots (because Google does that and users expect it).

12.8.4. Being popular

If you have a few jokes or links to resources or responses that are favorably received by your audience, in general, then respond with those rather than the best match for the question asked, especially if the match is low. And these jokes or resources may help bring your human back into a conversation path that you’re familiar with and have a lot of training set data for.

12.8.5. Be a connector

Chatbots that can be the hub of a social network will quickly be appreciated by their users. Introduce the human to other humans on the chat forum or people who’ve written about things the user has written about. Or point the user to a blog post, meme, chat channel, or other website that’s relevant to something they might be interested in. A good bot will have a handy list of popular links to hand out when the conversation starts to get repetitive.

Bot: You might like to meet @SuzyQ, she’s asked that question a lot lately. She might be able to help you figure it out.

12.8.6. Getting emotional

Google’s Inbox email responder is similar to the conversational chatbot problem we want to solve. The auto-responder must suggest a reply to the emails you receive based on their semantic content. But a long chain of replies is less likely for an email exchange. And the prompting text is generally much longer for an email auto-responder than it is for a conversational chatbot. Nonetheless, the problems both involve generating text replies to incoming text prompts. So many of the techniques for one may be applicable to the other.

Even though Google had access to billions of emails, the paired replies in the Gmail Inbox “Smart Reply” feature tend to funnel you toward short, generic, bland replies. A semantic search approach is likely to produce relatively generic, bland replies if you’re trying to maximize correctness for the average email user. The average reply isn’t likely to have much personality or emotion. So Google tapped an unlikely corpus to add a bit of emotion to their suggested replies... romance novels.

It turns out that romance novels tend to follow predictable plots and have sappy dialog that can be easily dissected and imitated. And it contains a lot of emotion. Now I’m not sure how Google gleaned phrases like “That’s awesome! Count me in!” or “How cool! I’ll be there.” from romance novels, but they claim that’s the source of the emotional exclamations that they suggest with Smart Reply.

12.9. In the real world

The hybrid chatbot you’ve assembled here has the flexibility to be used for the most common real-world applications. In fact, you’ve probably interacted with such a chatbot sometime this week:

  • Customer service assistants
  • Sales assistants
  • Marketing (spam) bots
  • Toy or companion bots
  • Video game AI
  • Mobile assistants
  • Home automation assistants
  • Visual interpreters
  • Therapist bots
  • Automated email reply suggestions

And you’re likely to run across chatbots like the ones you built in this chapter more and more. User interfaces are migrating away from designs constrained by the rigid logic and data structures of machines. More and more machines are being taught how to interact with us in natural, fluid conversation. The “voice first” design pattern is becoming more popular as chatbots become more useful and less frustrating. And these dialog system approaches promise a richer and more complex user experience than clicking buttons and swiping left. And with chatbots interacting with us behind the curtains, they are becoming more deeply embedded in the collective consciousness.

So now you’ve learned all about building chatbots for fun and for profit. And you’ve learned how to combine generative dialog models, semantic search, pattern matching, and information extraction (knowledge bases) to produce a chatbot that sounds surprisingly intelligent.

You’ve mastered all the key NLP components of an intelligent chatbot. Your only remaining challenge is to give it a personality of your own design. And then you’ll probably want to “scale it up” so it can continue to learn, long after you’ve exhausted the RAM, hard drive, and CPU in your laptop. And we show you how to do that in chapter 13.

Summary

  • By combining multiple proven approaches, you can build an intelligent dialog engine.
  • Breaking “ties” between the replies generated by the four main chatbot approaches is one key to intelligence.
  • You can teach machines a lifetime of knowledge without spending a lifetime programming them.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset