| Windows Live Ag... 的个人资料Windows Live Agents照片日志列表 | 帮助 |
|
7月29日 Visual Studio hintsIf 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.0When 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 IIThis 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 IAn 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 AgentAs 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! |
|
|