Windows Live Ag... 的个人资料Windows Live Agents照片日志列表 工具 帮助

日志


7月29日

Visual Studio hints

If you are moving from the old Colloquis IDE to the Visual Studio-based Windows Live Agents SDK, and you've never used Visual Studio, you may be a little lost.  This post aims to collect simple hints and tricks for agent developers new to working with Visual Studio.  This is just a start -- if you have any hints, please do comment, and later on we'll post a sequel. 
 
Also, this is by no means much of a guide to Visual Studio as a whole, and is really meant to get you started and oriented for agent-development tasks.  Also, it's not a guide for creating agents.  The first resource for using the new SDK is the Windows Live Agents SDK documentation.  You should start there before doing anything.
 
Agents menus
Here are some common menu locations for agent-development tasks:
 
Edit -> Find and Replace   ... Lots of options for searching through single or multiple files.  Regular expressions work!
View -> Solution Explorer ... This is rougly equivalent to the Explorer feature in the old IDE, and lets you see the project files in a tree view.
View -> Class View          ... Lets you see all the project's domains and packages as a flat list of classes.
View -> Error list             ... Displays compile errors and warnings.
View -> Output                ... Similar to the "Misc Debug" pane of the old IDE, displays compiler messages.
View -> Other Windows -> Conversation Window            ... Where you compile and talk to the agent.
View -> Other Windows -> Comprehension Info Window  ... Displays match scoring information.
Project -> Add DLS Item                ... Add datasources and other DLS items.
Project -> ProjectName Properties  ... Specify compile parameters like buddy id, filter, and command-line options.
Tools -> Windows Live Agents Tools -> Code Management              ... The SDK's interface to the Partner Hosting Infrastructure.
Tools -> Windows Live Agents Tools -> Request License Certificate  ... Get a new license cert.
Tools -> Windows Live Agents Tools -> Management Console          ... Launches the web management console within Visual Studio.
Tools -> Windows Live Agents Tools -> Update connections file        ... Attempts to update the connections file based on the content of your project.
Tools -> Windows Live Agents Tools -> Performance                       ... Various tools for measuring performance.
Tools -> Options ... Set things like tabs and syntax highlighting.
 
Show All Files
By default, the SDK will mount a filesystem in the Solution Explorer, which may affect performance if there are a lot of files, causing the editor to lag.  If this is the case, you can click "Show All Files" to remove the All Files view, and navigate to files through the Class View.  Editing will be a lot faster.  Set Show All Files to false by default at Tools -> Options -> Windows Live Agents SDK -> SDK Settings -> General -> "Show All Files on project open."
 
Keyboard Shorcuts 
As of right now, there isn't a keyboard shortcut for starting/stopping the agent in the Conversation Window.  However, here are some shorcuts you may find useful:
 
CTRL-K CTRL-C ... comment
CTRL-K CTRL-U ... uncomment
CTRL-ALT-L ... Solution Explorer
CTRL-TAB ... toggle through open windows
CTRL-Shift-<arrow key> ... move forward/backward by one word
 
Many other shortcuts are listed next to the menu items they correspond to.
 
Window Arrangement
One of the best things about Visual Studio is the flexibility it provides for laying out your environment.  Any window can be tabbed, docked, or floating, and you can drag everything around the way you like.  Right click a window title, or click the small arrow in the top of the pane, to see your options. 
 
7月17日

Definition of Reporting Terms in Usage Reporting in 5.0

 

When your agent launches, you will be given access to the Knowledge Management Server, which includes a Usage Reporting section. The URL is https://YourProjectName.console.agents.live.com.

 

When you navigate to the Usage Reporting site, you will see date range options in the left pane, and report results in the right pane.  The default date is the present day.  You can switch days by clicking on the calendar on the left.

 

If you click on “Custom Range” on the upper left side of the page, you can view usage reports for a custom date range. Please not that in this view, New & Unique Users will be shown as N/A. Due to a design limitation, we currently cannot provide accurate measurements of new and unique users for custom reporting periods.

 

At the top of the page, you may see the following sections of reporting: Volume Summary, User Demographics, Languages Used, Activity Usage, Compliance, Category Analysis, Topic Analysis, and Clickthroughs. The default reporting view is Volume Summary. The sections of Usage Reporting you see, depends on how you have set up the usage_config.xml your project uses. For more information on customizing the usage_config.xml, click here.

 

Definition of Reporting Terms: 

 

Volume Summary Section

 

Total Queries:             

The total number of queries in all sessions within the specified time period. For example, if the time period includes 100 sessions, there could be 1000 or more total queries.

 

Total Sessions:           

The total number of sessions within the specified time period.

 

Unique Users:             

The number of unique users within the specified time period. Each user is counted once, regardless of how often they interact with the agent. For example, if one person has ten separate sessions with the agent during the specified time period, they are still identified as one unique user.

 

New Users:                  

The number of users whose initial session with the agent occurred during the specified time period.

 

Average Queries Per Session:

Total queries within the specified time period divided by total sessions within the specified time period.

 

Average Sessions Per Unique Users:  

Number of unique users within the specified time period divided by total number of sessions within the specified time period.

 

Category & Topic Analysis Sections

 

Category Analysis is broken out into two sections: Category Distribution Per Query and Category Distribution Per Session. Category Distribution Per Query breaks down how many queries for the chosen date range matched to a category. Category Distribution Per Session breaks down how many times a query matched on a Category during a session.

 

Topic Analysis is only broken out into one section: Topic Distribution (By Query). This measures how many times users’ queries matched to a specific topic for the chosen date range.

 

For information on how to log Category and Topic Analysis in your project, click here.

 

Clickthrough Section

 

The Clickthrough section breaks down how many times a user is presented a link and how many times a user clicks on the link.

 

Total Impressions

Number of times a user is presented a link in their conversation with the bot.

 

Total Clicks

Number of times a user clicks on the link he / she is presented.

 

For information on tracking ClickThroughs in your project, click here.

 

Languages Used Section

 

Agent detects what languages users speak to the agent in.

 

Activity Usage Section

 

Tracks how many users accept or reject an invitation to open the Activity Window.

 

Compliance Section

 

Conversations Stopped

Number of conversations interrupted after detecting user was typing sensitive topics beyond the scope of the agent.

 

Sensitive Sequences Rejected

Number of answers that were blocked by the output filter, displaying an error message to the user.

 

Sensitive Sequences Trusted

Number of answers that would have been blocked by the output filter, but were let through because of the use of the tag <trusted>.

 

Answers Invoking Trust

Number of messages that were displayed with the tag <trusted>…</trusted> in them. It includes both messages that would have passed the output filter or failed it.

 

7月8日

An advanced look at Web Services and DataSources - Part II

This is a continuation on An Advanced Look at Web Services and DataSources.  The original entry is located here:   http://windowsliveagents.spaces.live.com/blog/cns!5BCD45E519E07634!711.entry
 

Now let’s take a look at the datasource itself.  The datasource essentially is a function itself, with arguments to pass, and variables to return. In the preprocess section, the POST_DATA variable where the XML SOAP request string was built is put into here.  In addition, the actual web service URL is stated here as well. 

 

In the preprocess section, there are also two built-in variables that can be used, LIMIT and OFFSET.  These two variables are used to ‘page’ results in a cursor.  In the example above, we look at LIMIT to populate a variable called MAXRESULTS. The MAXRESULTS variable is then used in the COUNT element (in this case 10) to bring back 10 results per request.  If the user needs more, then the datasource then starts at the next row and retrieves 10 more results.

 

The simple xml section is a hierarchical representation of the XML response from the SOAP API, to be flattened out into a 2-dimension look when the data is retrieved.  Indentation is used to signify a parent-child relationship. The {loop=content} statement acts as a loop within the XML, iterating through the XML.  The end nodes (highlighted in BOLD) are the fields that is used to capture information and passed back to the calling routine.  Note that fields can be skipped in the simple xml section if the user does not need it.

 

It should be noted here that by using simple xml to represent the XML response, there is no provision for providing a “dynamic” representation of the XML using simple xml.  So in essence, you would have to potentially write a different datasource function for each different search type in this case.  For generate an advanced datasource that could output differently depending on the search type would require outputting a datasource in Buddyscript. We’ll cover this in a different blog.

 

 

datasource LiveSearchAPI(SEARCH, CULTURE_INFO) => Title, Description, Url, Source, NewsYear, NewsMonth, NewsDay, NewsHour, NewsMinute, NewsSecond {expire="in 1 hour" continue_on_error="true" timeout="15" }

  preprocess

    if LIMIT>10 || LIMIT<=0

      MAXRESULTS = 10

    else

      MAXRESULTS = LIMIT

    FIELDLIST = "Title Description Url Source DateTime"

    POST_DATA = BuildSearchAPIPostData(SEARCH, "News", OFFSET, MAXRESULTS, CULTURE_INFO, FIELDLIST)

  http

    http://soap.search.msn.com:80/webservices.asmx

    header

      Accept: application/soap+xml

    postdata {encode=no}

      POST_DATA

  simple xml

    Envelope

      Body

        SearchResponse

          Response

            Responses

              SourceResponse

                Offset => RESULTOFFSET    // Where we're starting from.

                Total => TOTAL     // Total number of results.  

                Results

                  Result {loop=content}

                    Title

                    Description

                    Url

                    Source

                    DateTime

                      Year

                      Month

                      Day

                      Hour

                      Minute

                      Second

  postprocess

    INFO.Offset = RESULTOFFSET

    INFO.MaxCount = TOTAL

    return INFO

 

 

There are other datasource properties that should be considered to either increase performance and or deal with potential errors in accessing/retrieving information from the datasource.  The first one is the Timeout property.  You can specify this time in order to lengthen or shorten the time it takes before the datasource quits accessing the web service.  The default value is 10 seconds.  In our case, we have it at 15 seconds.  The next property is the continue_on_error property.  By changing this property to ‘yes’, execution will still continue and the datasource caller can retrieve the error message in the SYS.Data.Error variable.  This is only on those sources that call the ABErrorProc.  The final property is very important.  It is the Expire property.  This determines how long retrieved data should be valid, i.e. kept in cahsed memory.  The ability to cache retrieved data in memory will improve performance on retrieving information in the datasource.  You should consider these factors:

 

1) how often does the data change?

2) how often will the same retrieved data be asked again?

3) how large is the retrieved data set?

4) server memory cache size (N/A on hosted applications)

5) how fast does the web service perform?

 

All of these are considerations.  In our case, since news items change frequently, we’ll set it for a relatively short time period, say 1 hour. 

 

Examples of the Expire property:

 

Expire=”never” /* this is the default expiration for most non-Buddyscript datasources */

Expire=”in 1 hour”

Expire =”now”  /* no caching at all, same as “never” */

Expire=”tomorrow at 5am” /* Note that this time is the server time, not the client time.  In hosted applications, this is in GMT time */

 

The postprocess section is important for returning a range of information.  For datasources that do not handle the processing of data using offsets and limits (i.e. simple xml), if the postprocess section is missing, the processing QueryServer will process the data coming back from the datasource in its entirety. In cases where the output coming back is one entity or one row, or if the amount of data needed to be processed is small, the postprocess section is not needed.

 

  postprocess

    INFO.Offset = RESULTOFFSET

    INFO.MaxCount = TOTAL

    return INFO

 

Looking at the postprocess section, this section is used to set the offset and total count of rows in a variable.  This variable is then used by Buddyscript to control the display of output.

 

In this case, INFO is the name of an object variable. The names of the variables inside the object is Offset and MaxCount, and these values are populated from the datasource:

 

                Offset => RESULTOFFSET    // Where we're starting from.

                Total => TOTAL     // Total number of results.  

 

 

Finally, here is a crude routine to pass a request to the Live Search API, access the web service and display the contents of the data, using Buddyscript code to control the amount of data coming in.

 

? Tell me some news about STRING=Anything

  LOCALE="en-us"

  TITLE, DESCRIPTION, LINK, SOURCE, YEAR, MONTH, DAY, HOUR, MINUTE, SECOND = LiveSearchAPI(STRING, LOCALE) show 10

    * Here are the results:

    - TITLE, SOURCE

    * <blank/>

      <ifmore>Type "more" for more news.</ifmore>

  else

    - Sorry, no news sites were found for your input.  

 

In the input, you could ask a question such as “Tell me some news about Baron Davis” for example, and get back results that looks like this (notice that the output only contains 2 out of the 10 arguments returned, Title and Source):

 

Here are the results:

 

Baron Davis Going South, San Francisco Gate

The Baron Davis, Gilbert Arenas Switch-a-roo?, San Francisco Gate

Clippers set sights on Baron Davis, Los Angeles Times

Baron Davis on verge of signing with Clippers, Washington Post

NBA: Warriors trying to woo Brand, Newsday

Baron Davis becomes free agent, Chicago Sun-Times

Report: Davis to ditch Warriors for Clippers, FOXSports.com

Logo? Colors? History? Don't mean a thing if you ain't got that team, CBS Sportsline

Davis on verge of joining Clippers, CNN Sports Illustrated

Davis on verge of signing with Clippers, Salon

 

Type “more” for more news.

.

.

.

.

 

 

Notice that in the pattern routine, there is an option called SHOW 10.  This means to output 10 rows at a time.  Buddyscript will go to the output datasource to retrieve the information, which in this case happens to be exactly 10 rows, since the request was to buffer 10 rows per datasource request.  If the user were to type in “more”, another 10 rows will be retrieved from the datasource and 10 more rows will be displayed, and so on.  (Note that there is a Buddyscript variable named SYS.Presentation.Maxlength that also controls the number of characters that can be displayed on an IM client.  Depending on what this is set to, this number will also control the number of rows displayed back.)

 

With the SHOW command, this allows the user a quick and equivalent way of emulating a forward read-only cursor, i.e. displaying x number of rows of output at one time.  The other option would be to put the data into an object and loop through the object, displaying each row, which involved more coding. It’s very possible that for control purposes, the latter method is the right way to go, but for quick coding and display, SHOW is very powerful.

 

Hopefully you have gotten a chance to absorb the intricacies of using datasources by accessing a really powerful web service.  Thanks for your attention!

 

 
 

An advanced look at Web Services and Datasources - Part I

An advanced look at Web Services and Datasources

 

Back in February, we showed a basic example of accessing a web service and using a datasource to consume information from a web service. (Refer to: http://windowsliveagents.spaces.live.com/blog/cns!5BCD45E519E07634!443.entry) Today, we’ll take a further look at a real-world web service, and some further things you can do with a datasource to make your application perform better, and to potentially reduce coding effort.

 

Many agents rely on rich content in order to create a solid user experience.  Many times, this involves accessing an external data store, such as a web service. With some web services, you can parameterize your request in the URL itself, for example http:/URL?<input>.  More often, web services involve using request and response model via a SOAP API. 

 

The Windows Live Search API is a very powerful web service that does many things.  It allows a user to do searches on the web, news, images, as well as get dictionary, phonebook and spelling information. It provides a web service XML interface using a SOAP API, enabling you to submit requests and get back a response via XML.  For more information on the XML, refer to this link:  http://msdn.microsoft.com/en-us/library/bb251794.aspx

 

Using any number of XML tools, we can take a look at the WSDL of the Live Search API web service to see how a typical request and response is crafted.  The WSDL endpoint is this:

 

http://soap.search.msn.com/webservices.asmx?wsdl

 

For purposes of discussion, let’s say that we are going use a Web News search, searching for “Baron Davis”.  The query of “Baron Davis” is put into the Query element. There are numerous other elements that are part of the response.  They are highlighted in red. The XML response would look like this:

 

<?xml version="1.0" encoding="utf-16"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <Search xmlns="http://schemas.microsoft.com/MSNSearch/2005/09/fex">

      <Request>

        <AppID>your APP ID</AppID>

        <Query>Baron Davis</Query>

        <CultureInfo>en-us</CultureInfo>

        <SafeSearch>Moderate</SafeSearch>

        <Flags>None</Flags>

        <Location>

          <Latitude>0</Latitude>

          <Longitude>0</Longitude>

        </Location>

        <Requests>

          <SourceRequest>

            <Source>News</Source>

            <Offset>0</Offset>

            <Count>10</Count>

            <FileType />

            <ResultFields>All DateTime</ResultFields>

            <SearchTagFilters>

              <string />

            </SearchTagFilters>

          </SourceRequest>

        </Requests>

      </Request>

 

(Note that strangely enough, in the ResultFields element, putting in the request “All” usually returns back all fields In the case of a News request, this does not return back all fields. “All DateTime” will return all fields, plus the datetime in this case.)

 

The XML response looks like this, with output fields in bold:

 

<?xml version="1.0" encoding="utf-16"?>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <soapenv:Body>

    <SearchResponse xmlns="http://schemas.microsoft.com/MSNSearch/2005/09/fex">

      <Response>

        <Responses>

          <SourceResponse>

            <Source>News</Source>

            <Offset>0</Offset>

            <Total>31185</Total>

            <Results>

              <Result>

                <Title>NBA free agent roundup: Baron Davis to L.A.?</Title>

                <Description>Baron Davis has a verbal agreement with the Clippers, Gilbert Arenas likely is staying in Washington, and Elton Brand has a decision to make as NBA free agency opened with some surprises yesterday. The dominoes began to tumble when Davis surprised ... </Description>

<Url>http://www.newsday.com/sports/basketball/knicks/ny-spnba025749266jul02,0,2266274.story </Url>

<DisplayUrl>http://www.newsday.com/sports/basketball/knicks/ny-spnba025749266jul02,0,2266274.story</DisplayUrl>

                <Source>Newsday</Source>

                <DateTime>

                  <Year>2008</Year>

                  <Month>7</Month>

                  <Day>2</Day>

                  <Hour>15</Hour>

                  <Minute>26</Minute>

                  <Second>29</Second>

                </DateTime>

              </Result>

 

              <Result>

                <Title>Later Daze, Baron: Davis leaves Warriors for Clippers</Title>

                <Description>del.icio.us Less than 24 hours after Davis shocked the Warriors by walking away from the final year and $17.8 million left on his contract, the franchise guard delivered a second strike Tuesday afternoon. Davis agreed in principle with the Clippers ... </Description>

<Url>http://www.sfgate.com/cgi-bin/article.cgi?f=/c/a/2008/07/02/SPCF11ICKB.DTL</Url>

<DisplayUrl>http://www.sfgate.com/cgi-bin/article.cgi?f=/c/a/2008/07/02/SPCF11ICKB.DTL</DisplayUrl>

                <Source>San Francisco Gate</Source>

                <DateTime>

                  <Year>2008</Year>

                  <Month>7</Month>

                  <Day>2</Day>

                  <Hour>15</Hour>

                  <Minute>19</Minute>

                  <Second>20</Second>

                </DateTime>

              </Result>

             </Results>

          </SourceResponse>

        </Responses>

      </Response>

    </SearchResponse>

  </soapenv:Body>

</soapenv:Envelope>

 

 

For purposes of display, only 2 items are displayed, but in the real-life example, there are 31,185 articles on “Baron Davis” that were found.  The 31,185 is indicated in the <TOTAL> element in the response.  Note that not all 31,185 rows are retrieved.  The amount retrieved is regulated in the Preprocess block, in the built-in LIMIT and OFFSET variables. More on this later, when we describe the datasource.

 

Let’s take a look at how we generate the Buddyscript code to access this web service.

 

A typical datasource accessing XML might have header information that looks like this:

 

datasource dsSample(ARG1, ARG2, ARG3) => A1, B1, C1

  http

    http://someurl/sample.xml

  simple xml

     .

     .

     .

 

However, for a web service invoking SOAP messages, we have to build a request string, so we use the PreProcess section of a datasource to set a variable that will contain the request, along with other variables.  Thus, the beginning of the datasource would look like this instead:

 

datasource LiveSearchAPI(SEARCH, CULTURE_INFO) => Title, Description, Url, Source, NewsYear, NewsMonth, NewsDay, NewsHour, NewsMinute, NewsSecond {expire="in 1 hour" continue_on_error="true"}

  preprocess

    if LIMIT>10 || LIMIT<=0

      MAXRESULTS = 10

    else

      MAXRESULTS = LIMIT

    FIELDLIST = "Title Description Url Source DateTime"

    POST_DATA = BuildSearchAPIPostData(SEARCH, "News", OFFSET, MAXRESULTS, CULTURE_INFO, FIELDLIST)

  http

    http://soap.search.msn.com:80/webservices.asmx

    header

      Accept: application/soap+xml

    postdata {encode=no}

      POST_DATA

  simple xml

     .

     .

     .

 

 

We’ll describe the syntax of the datasource in more details later on, but for now, what’s important to point out is that a function is called to build the request string.  The function in this case is called BuildSearchAPIPostData and has a number of arguments.  Let’s take a look at the function:

 

 

function BuildSearchAPIPostData(SEARCH, TYPE, OFFSET, COUNT,CULTURE_INFO,

  FIELDLIST, RADIUS, LATITUDE, LONGITUDE)

  if (LATITUDE eq "")

    LATITUDE = 0

  if (LONGITUDE eq "")

    LONGITUDE = 0

  if (RADIUS eq "")

    RADIUS = 5

  POST_DATA =                         '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'

  POST_DATA = StringConcat(POST_DATA, '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http:/\/schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:tns="http://schemas.microsoft.com/MSNSearch/2005/09/fex" > <SOAP-ENV:Body>')

  POST_DATA = StringConcat(POST_DATA, ' <tns:Search xmlns:tns="http:/\/schemas.microsoft.com/MSNSearch/2005/09/fex"> <tns:Request>\n')

  POST_DATA = StringConcat(POST_DATA, '   <tns:AppID>', GetLiveSearchAPIAppID(), '</tns:AppID>\n')

  POST_DATA = StringConcat(POST_DATA, '   <tns:Query>', SEARCH , '</tns:Query>\n')

  POST_DATA = StringConcat(POST_DATA, '   <tns:CultureInfo>', CULTURE_INFO, '</tns:CultureInfo> <tns:SafeSearch>Moderate</tns:SafeSearch> <tns:Flags>None</tns:Flags>\n')

  POST_DATA = StringConcat(POST_DATA, '   <tns:Location>\n')

  POST_DATA = StringConcat(POST_DATA, '     <tns:Latitude>', LATITUDE, '</tns:Latitude>\n')

  POST_DATA = StringConcat(POST_DATA, '     <tns:Longitude>', LONGITUDE, '</tns:Longitude>\n')

  POST_DATA = StringConcat(POST_DATA, '     <tns:Radius>', RADIUS, '</tns:Radius>\n')

  POST_DATA = StringConcat(POST_DATA, '   </tns:Location>\n')  

  POST_DATA = StringConcat(POST_DATA, '   <tns:Requests> <tns:SourceRequest>\n')

  POST_DATA = StringConcat(POST_DATA, '     <tns:Source>', TYPE, '</tns:Source>\n') // Web / Ads / InlineAnswers / PhoneBook / WordBreaker / Spelling

  POST_DATA = StringConcat(POST_DATA, '     <tns:Offset>', OFFSET, '</tns:Offset> <tns:Count>', COUNT, '</tns:Count> <tns:ResultFields>', FIELDLIST, '</tns:ResultFields>\n')

  POST_DATA = StringConcat(POST_DATA, '   </tns:SourceRequest> </tns:Requests>\n')

  POST_DATA = StringConcat(POST_DATA, ' </tns:Request> </tns:Search>\n')

  POST_DATA = StringConcat(POST_DATA, '</SOAP-ENV:Body> </SOAP-ENV:Envelope>\n')

  return POST_DATA  

 

 

The function essentially uses the variable POST_DATA to build the request string.  If there are certain parameters without information, it defaults the information (e.g. LATITUDE).  The function also calls another function to get the Windows Live APP ID.  This APP ID is used in the Live Search API to determine individual access rights.  (See the Windows Live API for more information on obtaining this APP ID.)  The function itself simply looks like this:

 

function GetLiveSearchAPIAppID()

  return "ABCDE12345" 

 

where “ABCDE12345” is the App ID.

 

We'll take a look at the rest of the datasource and invoke code later this week.

 

7月2日

Guidelines for Testing your Agent

As compared to Web sites and traditional software applications, conversational agents are subject to some unique policy compliance risks. These risks arise because:

 

·         End users’ interactions with agents are freeform and unpredictable.

·         Agents often engage in human-like interactions and operate in messaging environments normally used for human-to-human communications, making end users and outside observers especially sensitive to inappropriate content or behavior.

 

Because of these unique risks, the Windows Live Agents team highly recommends that each Agent undergo manual testing for policy compliance prior to launching. Once testers have acquainted themselves with the task, approximately 4 to 8 hours of manual testing should provide a reasonable evaluation of the Agent’s policy compliance. Testers should:

 

·         Be native speakers

·         Have a good understanding of cultural and political factors that might determine whether an Agent’s content/behavior is appropriate

·         Be able to make judgments in the best interest of your public image and business interests in the market where the Agent will be released

·         Be willing to provoke the Agent to behave inappropriately (this requires creativity, persistence, and willingness/ability to imagine offensive and provocative user inputs)

·         Understand the Agent’s feature set

·         Ideally not have been directly involved in the Agent’s development

 

If your testing uncovers any issues that you need help triaging or fixing, please contact Windows Live Agents Partner Support (agentsu@microsoft.com). Send a transcript illustrating each issue, along with a description (in English) of what the issue is.

 

Overview for Testers

 

This document is intended to provide guidelines and advice for manual testing of Agents for policy compliance. It outlines specific types of subject matter to focus on, common Agent vulnerabilities, and specific tactics that you can use in an attempt to uncover issues in a given Agent.

 

This document is not a step-by-step test plan; nor is it by any means exhaustive. When performing compliance testing, there is no substitute for your own persistence and imagination. Furthermore, these guidelines do not currently prescribe any specific standards. You should apply your language and market expertise and your business judgment to determine whether the Agent’s behavior and content are acceptable. We strongly advise erring on the side of caution.

 

You should read this document to acquaint yourself with the subject of Agent policy compliance. You may find the specific examples to be a helpful starting point, but effective testing will require you to apply your knowledge of the language and market for which the Agent is intended, and of the specific Agent’s content and features.

 

In order to test effectively, you must be willing and able to imagine and try highly offensive and provocative user inputs. If you’re not comfortable with this task, then you should attempt to find someone who is.

 

Once you have acquainted yourself with the task, approximately 4-8 hours of manual testing should provide a reasonable evaluation of the Agent’s policy compliance.

Sensitive/Inappropriate subject matter to test

 

·         Profanity

·         Hate/Intolerance (with respect to race, gender, sexual orientation, religion, etc.)

·         Violence and criminal behavior

·         Drug use

·         Sexual content

·         Suicide

·         Culturally/Politically sensitive subjects in your market

Scenarios to test

 

·         Imagine you are one of the Agent’s target users

·         Imagine you are a child

·         Imagine you are a malicious user attempting to provoke inappropriate Agent behavior

Common Agent vulnerabilities

 

·         Agent may repeat (or “mirror”) user language without employing adequate safeguards

·         Agent may respond to the form of a user input without understanding the content

·         Agent may fail to recognize inappropriate or sensitive subject matter if the user employs creative/subtle phrasing

·         Agent may incorrectly determine an input to be inappropriate and in turn respond inappropriately

·         Agent may have “unsafe” catch-all responses (responses used when the user input is not understood at all)

 

Some specific tactics to try

 

·         See how the Agent responds to blatant abuse and provocation

·         Try to trick the agent into repeating an inappropriate word or phrase

·         Try to elicit an inappropriate opinion from the Agent

·         Try to elicit the Agent’s approval (explicit or implicit) of an inappropriate statement

·         Try to elicit inappropriate answers to formulaic questions (yes/no, how many, etc.)

·         Try to elicit inappropriate responses to commands/requests/statements

·         Try to trick the Agent into inferring inappropriate intent where there is none (and responding inappropriately)

7月1日

It's all about context, part deux!

Hi again! Here is the second part of our visit to the magical world of contexts. Yesterday we brushed on a few simple uses for them, now let's dive into a slightly more sensitive subject.

 

  Once the agent is hosted and public, you may want to block access to the agent temporarily, for instance if you rely heavily on external data sources that are experiencing an outage or just very slow.

In that case it's a good idea to keep the agent running normally for a limited set of superusers so they can work on the issue, while putting up an 'out of service' message for the general users.

 

 

//The message is by default empty. If it's not then the agent knows that we want it muted.

variable PUBLIC.OUTAGE_MESSAGE = ""

 

context AgentIsDisabled {out-of-context="0" in-context="1000" condition="!IsSuperUser() && PUBLIC.OUTAGE_MESSAGE ne \"\""}

 

start context AgentIsDisabled

 

+ =AnythingStrong

  - PUBLIC.OUTAGE_MESSAGE

 

end context AgentIsDisabled

 

// SuperUsers only an change the agent status. Easy! We've already prepared for that.

start context RestrictedStrings

 

+ disable agent REASON=AnythingRaw

  PUBLIC.OUTAGE_MESSAGE = REASON

 

+ enable agent

  PUBLIC.OUTAGE_MESSAGE = ""

 

end context RestrictedStrings

 

 

  Here the condition is simply to check if the outage message is empty or not, except for super users. They will continue to use the agent normally, and can reenable it whenever their experience is back to normal.

 

Now, there is one problem in this code... did you spot it?

Using a public variable like this in a context condition is pretty bad for performance. Indeed, it would mean that for each query of each user, the query server would need to lock access to the public variable in order to read it just to check the context condition.

It gets even more troublesome if you're on dual-box hosting and require a Stored Public Variable to propagate the outage across queryservers!

What is the solution then?

 One possible solution is to check the outage variable only once: at session start. All you need for this is to keep a local session variable of that setting.

 

 

stored variable PUBLIC.STORED_OUTAGE_MESSAGE = ""

variable G_OUTAGE_MESSAGE = ""

 

procedure ABStartSessionProc()

  // This procedure can exist independently in any buddyscript file, and is called at session start

  if !IsSuperUser()

    lock profile // locking is required for stored public variables.

      G_OUTAGE_MESSAGE = PUBLIC.STORED_OUTAGE_MESSAGE

 

context AgentIsDisabled {out-of-context="0" in-context="1000" condition="G_OUTAGE_MESSAGE ne \"\""} //note that we don't need to check for SuperUsers here as as it's done at session start

 

start context AgentIsDisabled

 

+ =AnythingStrong

  - G_OUTAGE_MESSAGE

 

end context AgentIsDisabled

 

start context RestrictedStrings

 

+ disable agent REASON=AnythingStrong

  lock profile

    PUBLIC.STORED_OUTAGE_MESSAGE = REASON

 

+ enable agent

  lock profile

    PUBLIC.STORED_OUTAGE_MESSAGE = ""

 

end context RestrictedStrings

 

  As you may have noticed, there is a caveat to this solution: since we only check the message at session start, the flag takes some time to propagate as only new users will be getting the message.

The same is true when you re-enable the agent and it will take a few minutes for the outage to be over for everyone.

 

  So here, we only lock the agent's profile and check the public stored variable once for every session, which is good already. But can we do better?

Imagine your agent is highly successful and deals with so many people that, say, five people start a new session every second. Don't we all dream of having an agent that popular! But it comes with a price: 5 calls to the public profile per second would probably bog the whole system down.

  What do you do then? Well, add yet another layer of buffering of course!

Back to our friend the "basic" public variable. That one only lives for the current queryserver, but it is a lot more performant to check against. All we'll need is a background procedure to update the public variable every few minutes, so as to transmit the orders from the top to the base:

 

 

stored variable PUBLIC.STORED_OUTAGE_MESSAGE_FOR_ALL_USERS = ""

variable        PUBLIC.OUTAGE_MESSAGE_FOR_ALL_USERS_OF_THIS_SERVER = ""

variable        G_OUTAGE_MESSAGE_FOR_THIS_USER = ""

 

procedure Background_UpdateOutageMessage() startup every 1 minute

  // This procedure is called at startup and every minute, independently of any user session.

  lock profile

    PUBLIC.OUTAGE_MESSAGE_FOR_ALL_USERS_OF_THIS_SERVER = PUBLIC.STORED_OUTAGE_MESSAGE_FOR_ALL_USERS

 

procedure ABStartSessionProc()

  if !IsSuperUser()

    G_OUTAGE_MESSAGE_FOR_THIS_USER = PUBLIC.OUTAGE_MESSAGE_FOR_ALL_USERS_OF_THIS_SERVER

 

context AgentIsDisabled {out-of-context="0" in-context="1000" condition="G_OUTAGE_MESSAGE_FOR_THIS_USER ne \"\""}

 

start context AgentIsDisabled

 

+ =AnythingStrong

  - G_OUTAGE_MESSAGE_FOR_THIS_USER

 

end context AgentIsDisabled

 

start context RestrictedStrings

 

+ disable agent REASON=AnythingStrong

  PUBLIC.STORED_OUTAGE_MESSAGE_FOR_ALL_USERS = REASON

 

+ enable agent

  PUBLIC.STORED_OUTAGE_MESSAGE_FOR_ALL_USERS = ""

 

end context RestrictedStrings

 

  Here you have a piece of code, slighly more complex, but that will sustain any kind of traffic without budging, with the only downside of taking up to one more minute to propagate the change of the agent's status.

 

 And this concludes our two-day tour of contexts and their natural habitat. I hope you liked it, and please don't forget to check out our gift shop on the way out!