Becerileri kullanarak başka bir botu genişletebilirsiniz.
Beceri, başka bir bot için bir dizi görev gerçekleştirebilen bir botdur.
Bildirim, becerinin arabirimini açıklar. Becerinin kaynak koduna erişimi olmayan geliştiriciler, beceri tüketicilerini tasarlamak için bildirimdeki bilgileri kullanabilir.
Bir beceri, hangi botların veya kullanıcıların erişebileceğini yönetmek için talep doğrulamasını kullanabilir.
Bu makale, kullanıcının girişini yankılayan bir becerinin nasıl uygulandığını gösterir.
Bazı beceri tüketicileri, bazı beceri botu türlerini kullanamaz.
Aşağıdaki tabloda hangi birleşimlerin desteklendiği açıklanmaktadır.
Çok kiracılı beceri
Tek kiracılı beceri
Kullanıcı tarafından atanan yönetilen kimlik becerisi
Çok kiracılı tüketici
Desteklenir
Desteklenmez
Desteklenmez
Tek kiracılı tüketici
Desteklenmez
Her iki uygulama da aynı kiracıya aitse desteklenir
Her iki uygulama da aynı kiracıya aitse desteklenir
Kullanıcı tarafından atanan yönetilen kimlik tüketicisi
Desteklenmez
Her iki uygulama da aynı kiracıya aitse desteklenir
Her iki uygulama da aynı kiracıya aitse desteklenir
Not
Bot Framework JavaScript, C# ve Python SDK'ları desteklenmeye devam edecektir, ancak Java SDK'sı son uzun vadeli destek Kasım 2023'te sona erecek şekilde kullanımdan kaldırılacaktır.
Java SDK ile oluşturulan mevcut botlar çalışmaya devam edecektir.
Yeni bot derlemesi için Microsoft Copilot Studio'yu kullanmayı göz önünde bulundurun ve doğru copilot çözümünü seçme hakkında bilgi edinin.
C#, JavaScript, Java veya Python'daki basit bot-bot becerileri örneğinin bir kopyası.
Not
Sürüm 4.11'den başlayarak, Bot Framework Öykünücüsü'nde bir beceriyi yerel olarak test etmek için bir uygulama kimliğine ve parolaya ihtiyacınız yoktur. Becerinizi Azure'a dağıtmak için yine de bir Azure aboneliği gereklidir.
Bu örnek hakkında
Basit bot-bot becerileri örneği iki bota yönelik projeleri içerir:
Beceriyi uygulayan yankı beceri botu.
Beceriyi kullanan bir kök botu uygulayan basit kök bot.
Bu makale, botundaki ve bağdaştırıcısındaki destek mantığını içeren beceriye odaklanır.
Basit kök bot hakkında bilgi için bkz. Beceri tüketicisi uygulama.
Kaynaklar
Dağıtılan botlar için bot-bot kimlik doğrulaması, katılan her bot için geçerli kimlik bilgilerine sahip olmasını gerektirir.
Ancak, çok kiracılı becerileri ve beceri tüketicilerini uygulama kimliği ve parolası olmadan Öykünücü ile yerel olarak test edebilirsiniz.
Beceriyi kullanıcıya yönelik botların kullanımına açmak için beceriyi Azure'a kaydedin. Daha fazla bilgi için bkz. Azure AI Bot Hizmeti ile bot kaydetme.
Uygulama yapılandırması
İsteğe bağlı olarak, becerinin kimlik bilgilerini yapılandırma dosyasına ekleyin. Beceri veya beceri tüketicisi kimlik bilgileri sağlıyorsa, her ikisi de sağlamalıdır.
İzin verilen arayanlar dizisi, hangi beceri tüketicilerinin beceriye erişebileceğini kısıtlayabilir.
Herhangi bir beceri tüketicisinden gelen çağrıları kabul etmek için bir "*" öğesi ekleyin.
Not
Becerinizi bot kimlik bilgileri olmadan yerel olarak test ediyorsanız, ne beceri ne de beceri tüketicisi talep doğrulama gerçekleştirmek için kodu çalıştırır.
İsteğe bağlı olarak, becerinin kimlik bilgilerini appsettings.json dosyasına ekleyin.
{
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": "",
// This is a comma separate list with the App IDs that will have access to the skill.
// This setting is used in AllowedCallersClaimsValidator.
// Examples:
// [ "*" ] allows all callers.
// [ "AppId1", "AppId2" ] only allows access to parent bots with "AppId1" and "AppId2".
"AllowedCallers": [ "*" ]
}
echo-skill-bot/.env
İsteğe bağlı olarak, becerinin kimlik bilgilerini .env dosyasına ekleyin.
İsteğe bağlı olarak, becerinin uygulama kimliğini ve parolasını application.properties dosyasına ekleyin.
MicrosoftAppId=
MicrosoftAppPassword=
server.port=39783
# This is a comma separate list with the App IDs that will have access to the skill.
# This setting is used in AllowedCallersClaimsValidator.
# Examples:
# * allows all callers.
# AppId1,AppId2 only allows access to parent bots with "AppId1" and "AppId2".
AllowedCallers=*
İsteğe bağlı olarak, becerinin uygulama kimliğini ve parolasını config.py dosyasına ekleyin.
config.py
APP_ID = os.environ.get("MicrosoftAppId", "")
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
APP_TYPE = os.environ.get("MicrosoftAppType", "MultiTenant")
APP_TENANTID = os.environ.get("MicrosoftAppTenantId", "")
# Callers to only those specified, '*' allows any caller.
Etkinlik işleyici mantığı
Giriş parametrelerini kabul etmek için
Beceri tüketicisi beceriye bilgi gönderebilir. Bu tür bilgileri kabul etmenin bir yolu, gelen iletilerde value özelliği aracılığıyla bunları kabul etmektir. Başka bir yol da olayı işlemek ve etkinlikleri çağırmaktır.
Bu örnekteki beceri giriş parametrelerini kabul etmiyor.
Konuşmaya devam etmek veya tamamlamak için
Beceri bir etkinlik gönderdiğinde, beceri tüketicisi etkinliği kullanıcıya iletmelidir.
Ancak beceri tamamlandığında bir endOfConversation etkinlik göndermeniz gerekir; aksi takdirde, beceri tüketicisi kullanıcı etkinliklerini beceriye iletmeye devam eder.
İsteğe bağlı olarak, bir dönüş değeri eklemek için etkinliğin value özelliğini kullanın ve becerinin neden sona erdiğini belirtmek için etkinliğin kod özelliğini kullanın.
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.Text.Contains("end") || turnContext.Activity.Text.Contains("stop"))
{
// Send End of conversation at the end.
var messageText = $"ending conversation from the skill...";
await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
var endOfConversation = Activity.CreateEndOfConversationActivity();
endOfConversation.Code = EndOfConversationCodes.CompletedSuccessfully;
await turnContext.SendActivityAsync(endOfConversation, cancellationToken);
}
else
{
var messageText = $"Echo: {turnContext.Activity.Text}";
await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
messageText = "Say \"end\" or \"stop\" and I'll end the conversation and back to the parent.";
await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput), cancellationToken);
}
}
echo-skill-bot/bot.js
this.onMessage(async (context, next) => {
switch (context.activity.text.toLowerCase()) {
case 'end':
case 'stop':
await context.sendActivity({
type: ActivityTypes.EndOfConversation,
code: EndOfConversationCodes.CompletedSuccessfully
});
break;
default:
await context.sendActivity(`Echo (JS) : '${ context.activity.text }'`);
await context.sendActivity('Say "end" or "stop" and I\'ll end the conversation and back to the parent.');
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
echoSkillBot\EchoBot.java
protected CompletableFuture<Void> onMessageActivity(TurnContext turnContext) {
if (
turnContext.getActivity().getText().contains("end") || turnContext.getActivity().getText().contains("stop")
) {
String messageText = "ending conversation from the skill...";
return turnContext.sendActivity(MessageFactory.text(messageText, messageText, InputHints.IGNORING_INPUT))
.thenApply(result -> {
Activity endOfConversation = Activity.createEndOfConversationActivity();
endOfConversation.setCode(EndOfConversationCodes.COMPLETED_SUCCESSFULLY);
return turnContext.sendActivity(endOfConversation);
})
.thenApply(finalResult -> null);
} else {
String messageText = String.format("Echo: %s", turnContext.getActivity().getText());
return turnContext.sendActivity(MessageFactory.text(messageText, messageText, InputHints.IGNORING_INPUT))
.thenApply(result -> {
String nextMessageText =
"Say \"end\" or \"stop\" and I'll end the conversation and back to the parent.";
return turnContext.sendActivity(
MessageFactory.text(nextMessageText, nextMessageText, InputHints.EXPECTING_INPUT)
);
})
.thenApply(result -> null);
}
}
echo-skill-bot/bots/echo_bot.py
async def on_message_activity(self, turn_context: TurnContext):
if "end" in turn_context.activity.text or "stop" in turn_context.activity.text:
# Send End of conversation at the end.
await turn_context.send_activity(
MessageFactory.text("Ending conversation from the skill...")
)
end_of_conversation = Activity(type=ActivityTypes.end_of_conversation)
end_of_conversation.code = EndOfConversationCodes.completed_successfully
await turn_context.send_activity(end_of_conversation)
else:
await turn_context.send_activity(
MessageFactory.text(f"Echo (python): {turn_context.activity.text}")
)
await turn_context.send_activity(
MessageFactory.text(
f'Say "end" or "stop" and I\'ll end the conversation and back to the parent.'
)
)
Beceriyi iptal etmek için
Çok aşamalı beceriler için, bir beceri tüketicisinden gelen etkinlikleri de kabul endOfConversation eder ve tüketicinin geçerli konuşmayı iptal etmesine izin verirsiniz.
Bu becerinin mantığı sırayla değişmez. Konuşma kaynaklarını ayıran bir beceri uygularsanız, konuşma sonu işleyicisine kaynak temizleme kodu ekleyin.
protected override Task OnEndOfConversationActivityAsync(ITurnContext<IEndOfConversationActivity> turnContext, CancellationToken cancellationToken)
{
// This will be called if the root bot is ending the conversation. Sending additional messages should be
// avoided as the conversation may have been deleted.
// Perform cleanup of resources if needed.
return Task.CompletedTask;
}
echo-skill-bot/bot.js
onUnrecognizedActivityType Konuşma sonu mantığı eklemek için yöntemini kullanın. İşleyicide tanınmayan etkinliğin type eşit endOfConversationolup olmadığını denetleyin.
this.onEndOfConversation(async (context, next) => {
// This will be called if the root bot is ending the conversation. Sending additional messages should be
// avoided as the conversation may have been deleted.
// Perform cleanup of resources if needed.
// By calling next() you ensure that the next BotHandler is run.
await next();
});
echoSkillBot\EchoBot.java
protected CompletableFuture<Void> onEndOfConversationActivity(TurnContext turnContext) {
// This will be called if the root bot is ending the conversation. Sending
// additional messages should be
// avoided as the conversation may have been deleted.
// Perform cleanup of resources if needed.
return CompletableFuture.completedFuture(null);
}
echo-skill-bot/bots/echo_bot.py
async def on_end_of_conversation_activity(self, turn_context: TurnContext):
# This will be called if the root bot is ending the conversation. Sending additional messages should be
# avoided as the conversation may have been deleted.
# Perform cleanup of resources if needed.
pass
Talep doğrulayıcı
Bu örnek, talep doğrulaması için izin verilen arayanlar listesini kullanır. Becerinin yapılandırma dosyası listeyi tanımlar. Doğrulayıcı nesnesi listeyi okur.
Kimlik doğrulama yapılandırmasına bir talep doğrulayıcı eklemeniz gerekir. Talepler kimlik doğrulama üst bilgisinde değerlendirilir. Doğrulama kodunuz isteği reddetmek için bir hata veya özel durum oluşturmalıdır. Aksi takdirde kimliği doğrulanmış bir isteği reddetmek istemeniz için birçok neden vardır. Örneğin:
Beceri, ücretli hizmetin bir parçasıdır. Kullanıcının veritabanında olmaması gerekir.
Beceri özeldir. Beceriyi yalnızca belirli beceri tüketicileri adlandırabilir.
Önemli
Talep doğrulayıcı sağlamazsanız botunuz beceri tüketicisinden etkinlik aldıktan sonra bir hata veya özel durum oluşturur.
SDK, beceriyi çağırmasına AllowedCallersClaimsValidator izin verilen uygulamaların basit bir kimlik listesine dayalı olarak uygulama düzeyinde yetkilendirme ekleyen bir sınıf sağlar. Listede yıldız işareti (*) varsa, tüm arayanlara izin verilir. Talep doğrulayıcı Startup.cs yapılandırılır.
SDK, beceriyi çağırmasına allowedCallersClaimsValidator izin verilen uygulamaların basit bir kimlik listesine dayalı olarak uygulama düzeyinde yetkilendirme ekleyen bir sınıf sağlar. Listede yıldız işareti (*) varsa, tüm arayanlara izin verilir. Talep doğrulayıcı index.js'de yapılandırılır.
SDK, beceriyi çağırmasına AllowedCallersClaimsValidator izin verilen uygulamaların basit bir kimlik listesine dayalı olarak uygulama düzeyinde yetkilendirme ekleyen bir sınıf sağlar. Listede yıldız işareti (*) varsa, tüm arayanlara izin verilir. Talep doğrulayıcı Application.java yapılandırılır.
Gelen isteği reddetmek için hata oluşturan bir talep doğrulama yöntemi tanımlayın.
class AllowedCallersClaimsValidator:
config_key = "ALLOWED_CALLERS"
def __init__(self, config: DefaultConfig):
if not config:
raise TypeError(
"AllowedCallersClaimsValidator: config object cannot be None."
)
# ALLOWED_CALLERS is the setting in config.py file
# that consists of the list of parent bot ids that are allowed to access the skill
# to add a new parent bot simply go to the AllowedCallers and add
# the parent bot's microsoft app id to the list
caller_list = getattr(config, self.config_key)
if caller_list is None:
raise TypeError(f'"{self.config_key}" not found in configuration.')
self._allowed_callers = frozenset(caller_list)
@property
def claims_validator(self) -> Callable[[List[Dict]], Awaitable]:
async def allow_callers_claims_validator(claims: Dict[str, object]):
# if allowed_callers is None we allow all calls
if "*" not in self._allowed_callers and SkillValidation.is_skill_claim(
claims
):
# Check that the appId claim in the skill request is in the list of skills configured for this bot.
app_id = JwtTokenValidation.get_app_id_from_claims(claims)
if app_id not in self._allowed_callers:
raise PermissionError(
f'Received a request from a bot with an app ID of "{app_id}".'
f" To enable requests from this caller, add the app ID to your configuration file."
)
return
return allow_callers_claims_validator
Beceri bağdaştırıcısı
Bir hata oluştuğunda, becerinin bağdaştırıcısı becerinin konuşma durumunu temizlemeli ve ayrıca beceri tüketicisine bir endOfConversation etkinlik göndermelidir. Becerinin bir hata nedeniyle sona erdiğinin sinyalini vermek için etkinliğin kod özelliğini kullanın.
private async Task HandleTurnError(ITurnContext turnContext, Exception exception)
{
// Log any leaked exception from the application.
_logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
await SendErrorMessageAsync(turnContext, exception);
await SendEoCToParentAsync(turnContext, exception);
}
private async Task SendErrorMessageAsync(ITurnContext turnContext, Exception exception)
{
try
{
// Send a message to the user.
var errorMessageText = "The skill encountered an error or bug.";
var errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.IgnoringInput);
await turnContext.SendActivityAsync(errorMessage);
errorMessageText = "To continue to run this bot, please fix the bot source code.";
errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.ExpectingInput);
await turnContext.SendActivityAsync(errorMessage);
// Send a trace activity, which will be displayed in the Bot Framework Emulator.
// Note: we return the entire exception in the value property to help the developer;
// this should not be done in production.
await turnContext.TraceActivityAsync("OnTurnError Trace", exception.ToString(), "https://www.botframework.com/schemas/error", "TurnError");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Exception caught in SendErrorMessageAsync : {ex}");
}
}
private async Task SendEoCToParentAsync(ITurnContext turnContext, Exception exception)
{
try
{
// Send an EndOfConversation activity to the skill caller with the error to end the conversation,
// and let the caller decide what to do.
var endOfConversation = Activity.CreateEndOfConversationActivity();
endOfConversation.Code = "SkillError";
endOfConversation.Text = exception.Message;
await turnContext.SendActivityAsync(endOfConversation);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Exception caught in SendEoCToParentAsync : {ex}");
}
}
echo-skill-bot/index.js
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to the console log, instead of to app insights.
// NOTE: In a production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${ error }`);
await sendErrorMessage(context, error);
await sendEoCToParent(context, error);
};
async function sendErrorMessage(context, error) {
try {
// Send a message to the user.
let onTurnErrorMessage = 'The skill encountered an error or bug.';
await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
onTurnErrorMessage = 'To continue to run this bot, please fix the bot source code.';
await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
// Send a trace activity, which will be displayed in the Bot Framework Emulator.
// Note: we return the entire exception in the value property to help the developer;
// this should not be done in production.
await context.sendTraceActivity('OnTurnError Trace', error.toString(), 'https://www.botframework.com/schemas/error', 'TurnError');
} catch (err) {
console.error(`\n [onTurnError] Exception caught in sendErrorMessage: ${ err }`);
}
}
async function sendEoCToParent(context, error) {
try {
// Send an EndOfConversation activity to the skill caller with the error to end the conversation,
// and let the caller decide what to do.
const endOfConversation = {
type: ActivityTypes.EndOfConversation,
code: 'SkillError',
text: error.toString()
};
await context.sendActivity(endOfConversation);
} catch (err) {
console.error(`\n [onTurnError] Exception caught in sendEoCToParent: ${ err }`);
}
}
echoSkillBot\SkillAdapterWithErrorHandler.java
public SkillAdapterWithErrorHandler(
Configuration configuration,
AuthenticationConfiguration authenticationConfiguration
) {
super(configuration, authenticationConfiguration);
setOnTurnError(new SkillAdapterErrorHandler());
}
private class SkillAdapterErrorHandler implements OnTurnErrorHandler {
@Override
public CompletableFuture<Void> invoke(TurnContext turnContext, Throwable exception) {
return sendErrorMessage(turnContext, exception).thenAccept(result -> {
sendEoCToParent(turnContext, exception);
});
}
private CompletableFuture<Void> sendErrorMessage(TurnContext turnContext, Throwable exception) {
try {
// Send a message to the user.
String errorMessageText = "The skill encountered an error or bug.";
Activity errorMessage =
MessageFactory.text(errorMessageText, errorMessageText, InputHints.IGNORING_INPUT);
return turnContext.sendActivity(errorMessage).thenAccept(result -> {
String secondLineMessageText = "To continue to run this bot, please fix the bot source code.";
Activity secondErrorMessage =
MessageFactory.text(secondLineMessageText, secondLineMessageText, InputHints.EXPECTING_INPUT);
turnContext.sendActivity(secondErrorMessage)
.thenApply(
sendResult -> {
// Send a trace activity, which will be displayed in the Bot Framework Emulator.
// Note: we return the entire exception in the value property to help the
// developer;
// this should not be done in production.
return TurnContext.traceActivity(
turnContext,
String.format("OnTurnError Trace %s", exception.toString())
);
}
);
});
} catch (Exception ex) {
return Async.completeExceptionally(ex);
}
}
private CompletableFuture<Void> sendEoCToParent(TurnContext turnContext, Throwable exception) {
try {
// Send an EndOfConversation activity to the skill caller with the error to end
// the conversation,
// and let the caller decide what to do.
Activity endOfConversation = Activity.createEndOfConversationActivity();
endOfConversation.setCode(EndOfConversationCodes.SKILL_ERROR);
endOfConversation.setText(exception.getMessage());
return turnContext.sendActivity(endOfConversation).thenApply(result -> null);
} catch (Exception ex) {
return Async.completeExceptionally(ex);
}
}
}
echo-skill-bot/adapter_with_error_handler.py
# This check writes out errors to console log
# NOTE: In production environment, you should consider logging this to Azure
# application insights.
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
traceback.print_exc()
await self._send_error_message(turn_context, error)
await self._send_eoc_to_parent(turn_context, error)
async def _send_error_message(self, turn_context: TurnContext, error: Exception):
try:
# Send a message to the user.
error_message_text = "The skill encountered an error or bug."
error_message = MessageFactory.text(
error_message_text, error_message_text, InputHints.ignoring_input
)
await turn_context.send_activity(error_message)
error_message_text = (
"To continue to run this bot, please fix the bot source code."
)
error_message = MessageFactory.text(
error_message_text, error_message_text, InputHints.ignoring_input
)
await turn_context.send_activity(error_message)
# Send a trace activity, which will be displayed in Bot Framework Emulator.
await turn_context.send_trace_activity(
label="TurnError",
name="on_turn_error Trace",
value=f"{error}",
value_type="https://www.botframework.com/schemas/error",
)
except Exception as exception:
print(
f"\n Exception caught on _send_error_message : {exception}",
file=sys.stderr,
)
traceback.print_exc()
async def _send_eoc_to_parent(self, turn_context: TurnContext, error: Exception):
try:
# Send an EndOfConversation activity to the skill caller with the error to end the conversation,
# and let the caller decide what to do.
end_of_conversation = Activity(type=ActivityTypes.end_of_conversation)
end_of_conversation.code = "SkillError"
end_of_conversation.text = str(error)
await turn_context.send_activity(end_of_conversation)
except Exception as exception:
print(
f"\n Exception caught on _send_eoc_to_parent : {exception}",
file=sys.stderr,
)
traceback.print_exc()
Hizmet kaydı
Bot Framework bağdaştırıcısı, gelen isteklerde kimlik doğrulama üst bilgisini doğrulamak için bir kimlik doğrulama yapılandırma nesnesi (bağdaştırıcı oluşturulduğunda ayarlanır) kullanır.
Bu örnek, kimlik doğrulama yapılandırmasına talep doğrulaması ekler ve beceri bağdaştırıcısını önceki bölümde açıklanan hata işleyicisi ile kullanır.
options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
});
// Register AuthConfiguration to enable custom claim validation.
services.AddSingleton(sp =>
{
var allowedCallers = new List<string>(sp.GetService<IConfiguration>().GetSection("AllowedCallers").Get<string[]>());
var claimsValidator = new AllowedCallersClaimsValidator(allowedCallers);
// If TenantId is specified in config, add the tenant as a valid JWT token issuer for Bot to Skill conversation.
// The token issuer for MSI and single tenant scenarios will be the tenant where the bot is registered.
var validTokenIssuers = new List<string>();
var tenantId = sp.GetService<IConfiguration>().GetSection(MicrosoftAppCredentials.MicrosoftAppTenantIdKey)?.Value;
if (!string.IsNullOrWhiteSpace(tenantId))
{
// For SingleTenant/MSI auth, the JWT tokens will be issued from the bot's home tenant.
// Therefore, these issuers need to be added to the list of valid token issuers for authenticating activity requests.
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV1, tenantId));
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV2, tenantId));
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1, tenantId));
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2, tenantId));
}
return new AuthenticationConfiguration
{
ClaimsValidator = claimsValidator,
ValidTokenIssuers = validTokenIssuers
};
});
// Create the Bot Framework Authentication to be used with the Bot Adapter.
services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
echo-skill-bot/index.js
const allowedCallers = (process.env.AllowedCallers || '').split(',').filter((val) => val) || [];
const claimsValidators = allowedCallersClaimsValidator(allowedCallers);
// If the MicrosoftAppTenantId is specified in the environment config, add the tenant as a valid JWT token issuer for Bot to Skill conversation.
// The token issuer for MSI and single tenant scenarios will be the tenant where the bot is registered.
let validTokenIssuers = [];
const { MicrosoftAppTenantId } = process.env;
if (MicrosoftAppTenantId) {
// For SingleTenant/MSI auth, the JWT tokens will be issued from the bot's home tenant.
// Therefore, these issuers need to be added to the list of valid token issuers for authenticating activity requests.
validTokenIssuers = [
`${ AuthenticationConstants.ValidTokenIssuerUrlTemplateV1 }${ MicrosoftAppTenantId }/`,
`${ AuthenticationConstants.ValidTokenIssuerUrlTemplateV2 }${ MicrosoftAppTenantId }/v2.0/`,
`${ AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1 }${ MicrosoftAppTenantId }/`,
`${ AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2 }${ MicrosoftAppTenantId }/v2.0/`
];
}
// Define our authentication configuration.
const authConfig = new AuthenticationConfiguration([], claimsValidators, validTokenIssuers);
const credentialsFactory = new ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: process.env.MicrosoftAppId,
MicrosoftAppPassword: process.env.MicrosoftAppPassword,
MicrosoftAppType: process.env.MicrosoftAppType,
MicrosoftAppTenantId: process.env.MicrosoftAppTenantId
});
const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(process.env, credentialsFactory, authConfig);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new CloudAdapter(botFrameworkAuthentication);
echoSkillBot\Application.java
@Override
public AuthenticationConfiguration getAuthenticationConfiguration(Configuration configuration) {
AuthenticationConfiguration authenticationConfiguration = new AuthenticationConfiguration();
authenticationConfiguration.setClaimsValidator(
new AllowedCallersClaimsValidator(Arrays.asList(configuration.getProperties(configKey)))
);
return authenticationConfiguration;
}
echo-skill-bot/app.py
CLAIMS_VALIDATOR = AllowedCallersClaimsValidator(CONFIG)
AUTH_CONFIG = AuthenticationConfiguration(
claims_validator=CLAIMS_VALIDATOR.claims_validator
)
# Create adapter.
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
SETTINGS = ConfigurationBotFrameworkAuthentication(
CONFIG,
auth_configuration=AUTH_CONFIG,
)
ADAPTER = AdapterWithErrorHandler(SETTINGS)
Beceri bildirimi
Beceri bildirimi, becerinin gerçekleştirebileceği etkinlikleri, giriş ve çıkış parametrelerini ve becerinin uç noktalarını açıklayan bir JSON dosyasıdır.
Bildirim, beceriye başka bir bottan erişmek için ihtiyacınız olan bilgileri içerir.
En son şema sürümü v2.1'dir.
{
"$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
"$id": "EchoSkillBot",
"name": "Echo Skill bot",
"version": "1.0",
"description": "This is a sample echo skill",
"publisherName": "Microsoft",
"privacyUrl": "https://echoskillbot.contoso.com/privacy.html",
"copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
"license": "",
"iconUrl": "https://echoskillbot.contoso.com/icon.png",
"tags": [
"sample",
"echo"
],
"endpoints": [
{
"name": "default",
"protocol": "BotFrameworkV3",
"description": "Default endpoint for the skill",
"endpointUrl": "http://echoskillbot.contoso.com/api/messages",
"msAppId": "00000000-0000-0000-0000-000000000000"
}
]
}
Beceri bildirimi şeması , beceri bildiriminin şemasını açıklayan bir JSON dosyasıdır. Geçerli şema sürümü 2.1.0'dır.
Beceriyi test edin
Bu noktada Emulator'daki beceriyi normal bir bot gibi test edebilirsiniz. Ancak, beceri olarak test etmek için bir beceri tüketicisi uygulamanız gerekir.
Yankı beceri botunu makinenizde yerel olarak çalıştırın. Yönergelere ihtiyacınız varsa C#, JavaScript, Java veya Python örneği için dosyaya bakınREADME.
Botu test etmek için Öykünücü'yü kullanın. Beceriye bir "son" veya "durdur" iletisi gönderdiğinizde, yanıt iletisine ek olarak bir endOfConversation etkinlik gönderir. Beceri, becerinin endOfConversation bittiğini belirtmek için etkinliği gönderir.
Hata ayıklama hakkında daha fazla bilgi
Beceri ve beceri tüketicileri arasındaki trafiğin kimliği doğrulandığından, bu tür botlarda hata ayıklama sırasında ek adımlar vardır.
Beceri tüketicisi ve doğrudan veya dolaylı olarak tükettiği tüm beceriler çalışıyor olmalıdır.
Botlar yerel olarak çalışıyorsa ve botlardan herhangi birinin uygulama kimliği ve parolası varsa, tüm botların geçerli kimlikleri ve parolaları olmalıdır.
Botlardan bazıları yerel olarak çalışıyorsa ve bazıları dağıtıldıysa, beceri veya beceri tüketicisinde hata ayıklamayı öğrenin.
Aksi takdirde, bir beceri tüketicisinde veya beceride, diğer botlarda hata ayıkladığınız gibi hata ayıklayabilirsiniz. Daha fazla bilgi için bkz. Botta hata ayıklama ve Bot Framework Öykünücüsü ile Hata Ayıklama.