Formato de arquivo .lg
APLICA-SE A: SDK v4
O arquivo .lg descreve os modelos de geração de linguagem com referências de entidade e a respectiva composição. Este artigo aborda os vários conceitos expressos com o formato de arquivo.
Caracteres Especiais
Comentários
Use > para criar um comentário. Todas as linhas que tenham esse prefixo serão ignoradas pelo analisador.
> This is a comment.
Caractere de escape
Use \ como um caractere de escape.
# TemplateName
- You can say cheese and tomato \[toppings are optional\]
Matrizes e objetos
Criar uma matriz
Para criar uma matriz, use a sintaxe ${[object1, object2, ...]}. Por exemplo, a expressão:
${['a', 'b', 'c']}
Retorna uma matriz ['a', 'b', 'c']
.
Criar um objeto
Para criar um objeto, use a sintaxe ${{key1:value1, key2:value2, ...}}. Por exemplo, a expressão:
${{user: {name: "Wilson", age: 27}}}
Retorna o seguinte objeto JSON:
{
"user": {
"name": "Wilson",
"age": 27
}
}
Modelos
Os modelos são o conceito básico do sistema de geração de linguagem. Cada modelo tem um nome e um dos seguintes:
- uma lista de valores de texto de variação one-of
- uma definição de conteúdo estruturado
- uma coleção de condições, cada uma com:
- uma expressão adaptável
- uma lista de valores de texto de variação one-of por condição
Nomes de modelo
Os nomes de modelo diferenciam maiúsculas de minúsculas e só podem conter letras, sublinhados e números. Veja a seguir um exemplo de modelo chamado TemplateName
.
# TemplateName
Os modelos não podem começar com um número e nenhuma parte de um nome de modelo dividida por . Não podem começar com um número.
Variações de resposta do modelo
As variações são expressas como uma lista Markdown. Você pode prefixar cada variação usando o caractere -, ' ou +.
# Template1
- text variation 1
- text variation 2
- one
- two
# Template2
* text variation 1
* text variation 2
# Template3
+ one
+ two
Modelo de resposta simples
Um modelo de resposta simples inclui uma ou mais variações de texto que são usadas para composição e expansão. Uma das variações fornecidas será selecionada aleatoriamente pela biblioteca LG.
Este é um exemplo de um modelo simples que inclui duas variações.
> Greeting template with two variations.
# GreetingPrefix
- Hi
- Hello
Modelo de resposta condicional
Os modelos de resposta condicional permitem criar um conteúdo selecionado com base em uma condição. Todas as condições são expressas por meio de expressões adaptáveis.
Importante
Os modelos condicionais não podem ser aninhados em um só modelo de resposta condicional. Use a composição em um modelo de resposta estruturada para aninhar condicionais.
Modelo if-else
O modelo if-else permite criar um modelo que escolhe uma coleção com base em uma ordem de condições em cascata. A avaliação é feita de cima para baixo e para quando uma condição é avaliada como true
ou o bloco ELSE é atingido.
As expressões condicionais são colocadas entre chaves ${}. Este é um exemplo que mostra uma definição de modelo de resposta condicional IF ELSE simples.
> time of day greeting reply template with conditions.
# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
- good morning
- ELSE:
- good evening
Este é outro exemplo que mostra uma definição de modelo de resposta condicional if-else. Observe que você pode incluir referências a outros modelos de resposta simples ou condicional na variação de uma das condições.
# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
- ${morningTemplate()}
- ELSEIF: ${timeOfDay == 'afternoon'}
- ${afternoonTemplate()}
- ELSE:
- I love the evenings! Just saying. ${eveningTemplate()}
Modelo de opção
O modelo de opção permite projetar um modelo que corresponda ao valor de uma expressão a uma cláusula CASE e produz a saída com base nesse caso. As expressões de condição são colocadas entre chaves ${}.
Veja como você pode especificar um bloco SWITCH CASE DEFAULT na LG.
# TestTemplate
- SWITCH: ${condition}
- CASE: ${case-expression-1}
- output1
- CASE: ${case-expression-2}
- output2
- DEFAULT:
- final output
Veja um exemplo mais complicado de SWITCH CASE DEFAULT:
> Note: Any of the cases can include reference to one or more templates.
# greetInAWeek
- SWITCH: ${dayOfWeek(utcNow())}
- CASE: ${0}
- Happy Sunday!
-CASE: ${6}
- Happy Saturday!
-DEFAULT:
- ${apology-phrase()}, ${defaultResponseTemplate()}
Observação
Assim como os modelos condicionais, os modelos de opção também não podem ser aninhados.
Modelo de resposta estruturada
Os modelos de resposta estruturada permitem definir uma estrutura complexa que dá suporte à principal funcionalidade de LG, como criação de modelos, composição e substituição, deixando a interpretação da resposta estruturada para o chamador da biblioteca LG.
Para aplicativos de bot, damos suporte nativo à:
- definição de atividade
- definição de cartão
Leia mais sobre os modelos de resposta estruturada para obter mais informações.
Composição e expansão de modelo
Referências a modelos
O texto de variação pode incluir referências a outro modelo nomeado para auxiliar na composição e na resolução de respostas sofisticadas. Referências a outros modelos nomeados são indicadas por meio de chaves, como ${<TemplateName>()}.
> Example of a template that includes composition reference to another template.
# GreetingReply
- ${GreetingPrefix()}, ${timeOfDayGreeting()}
# GreetingPrefix
- Hi
- Hello
# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
- good morning
- ELSEIF: ${timeOfDay == 'afternoon'}
- good afternoon
- ELSE:
- good evening
A chamada do modelo GreetingReply
pode resultar em uma das seguintes resoluções de expansão:
Hi, good morning
Hi, good afternoon
Hi, good evening
Hello, good morning
Hello, good afternoon
Hello, good evening
Entities
Quando usadas diretamente em um texto de variação one-of, as referências de entidade são indicadas colocando-as entre chaves, como ${entityName
}, ou sem chaves quando usadas como um parâmetro.
As entidades podem ser usadas como um parâmetro:
- dentro de uma função predefinida
- dentro de uma condição em um modelo de resposta condicional
- para a chamada de resolução de modelo
Como usar funções predefinidas em variações
As funções predefinidas compatíveis com as expressões adaptáveis também podem ser usadas embutidas em um texto de variação one-of para obter uma composição de texto ainda mais eficiente. Para usar uma expressão embutida, basta encapsulá-la entre chaves.
# RecentTasks
- IF: ${count(recentTasks) == 1}
- Your most recent task is ${recentTasks[0]}. You can let me know if you want to add or complete a task.
- ELSEIF: ${count(recentTasks) == 2}
- Your most recent tasks are ${join(recentTasks, ', ', ' and ')}. You can let me know if you want to add or complete a task.
- ELSEIF: ${count(recentTasks) > 2}
- Your most recent ${count(recentTasks)} tasks are ${join(recentTasks, ', ', ' and ')}. You can let me know if you want to add or complete a task.
- ELSE:
- You don't have any tasks.
O exemplo acima usa a função predefinida join para listar todos os valores na coleção recentTasks
.
Determinados modelos e funções predefinidas compartilham a assinatura de invocação, mas um modelo não pode ter o mesmo nome de uma função predefinida.
Um nome de modelo não deve corresponder a um nome de função predefinida. A função predefinida tem precedência. Para evitar esses conflitos, você pode preceder lg.
ao referenciar o nome do modelo. Por exemplo:
> Custom length function with one parameter.
# length(a)
- This is use's customized length function
# myfunc1
> will call prebuilt function length, and return 2
- ${length('hi')}
# mufunc2
> this calls the lg template and output 'This is use's customized length function'
- ${lg.length('hi')}
Texto multilinha em variações
Cada variação one-of pode incluir um texto multilinha entre aspas triplas.
# MultiLineExample
- ```This is a multiline list
- one
- two
```
- ```This is a multiline variation
- three
- four
```
A variação multilinha pode solicitar a expansão do modelo e a substituição da entidade colocando a operação solicitada entre chaves, ${}.
# MultiLineExample
- ```
Here is what I have for the order
- Title: ${reservation.title}
- Location: ${reservation.location}
- Date/ time: ${reservation.dateTimeReadBack}
```
Com o suporte multilinha, você pode fazer com que o subsistema de Geração de Linguagem resolva totalmente um JSON ou um XML complexo (como um texto encapsulado de SSML para controlar a resposta falada do bot).
Parametrização de modelos
Para auxiliar na capacidade de reutilização contextual, os modelos podem ser parametrizados. Chamadores diferentes do modelo podem passar valores diferentes para uso na resolução de expansão.
# timeOfDayGreetingTemplate (param1)
- IF: ${param1 == 'morning'}
- good morning
- ELSEIF: ${param1 == 'afternoon'}
- good afternoon
- ELSE:
- good evening
# morningGreeting
- ${timeOfDayGreetingTemplate('morning')}
# timeOfDayGreeting
- ${timeOfDayGreetingTemplate(timeOfDay)}
Como importar referências externas
Você pode dividir os modelos de geração de linguagem em arquivos separados e referenciar um modelo de um arquivo em outro. Use links no estilo Markdown para importar os modelos definidos em outro arquivo.
[Link description](filePathOrUri)
Todos os modelos definidos no arquivo de destino serão recebidos. Verifique se os nomes de modelo são exclusivos (ou têm o namespace # \<namespace>.\<templatename>
) em todos os arquivos que estão sendo recebidos.
[Shared](../shared/common.lg)
Funções injetadas pela LG
As expressões adaptáveis fornecem a capacidade de injetar um conjunto personalizado de funções. Leia Funções injetadas da biblioteca LG para obter mais informações.
Opções
O desenvolvedor pode definir opções do analisador para personalizar ainda mais a forma como a entrada é avaliada. Use a notação > !#
para definir as opções do analisador.
Importante
A última configuração encontrada no arquivo prevalece sobre todas as configurações anteriores encontradas no mesmo documento.
Opção strict
Os desenvolvedores que não desejam permitir um resultado nulo para um resultado avaliado como nulo poderão implementar a opção strict. Veja abaixo um exemplo de uma opção strict simples:
> !# @strict = true
# template
- hi
Se a opção strict estiver ativada, os erros nulos vão gerar uma mensagem amigável.
# welcome
- hi ${name}
Se o nome for nulo, o diagnóstico será 'name' avaliado como nulo. [welcome] Erro ao avaliar '- olá, ${name}'.. Se strict for definido como falso ou não for definido, um resultado compatível será fornecido. A amostra acima produzirá olá, nulo.
Opção replaceNull
Os desenvolvedores podem criar representantes para substituir valores nulos em expressões avaliadas usando a opção replaceNull:
> !# @replaceNull = ${path} is undefined
No exemplo acima, a entrada nula na variável path
será substituída por ${path} é indefinido. A seguinte entrada, em que user.name
é nulo:
hi ${user.name}
Resultará em olá, user.name é indefinido.
Opção lineBreakStyle
Os desenvolvedores podem definir opções de como o sistema LG renderiza as quebras de linha usando a opção lineBreakStyle. Atualmente, há suporte para dois modos:
default
: as quebras de linha no texto multilinha criam quebras de linha normais.markdown
: as quebras de linha no texto multilinha serão automaticamente convertidas em duas linhas para criar outra linha
O exemplo abaixo mostra como definir a opção lineBreakStyle como markdown
:
> !# @lineBreakStyle = markdown
Opção de namespace
Você pode registrar um namespace para os modelos LG que deseja exportar. Se não houver nenhum namespace especificado, o namespace será definido como o nome de arquivo sem uma extensão.
O seguinte exemplo mostra como definir a opção de namespace como foo
:
> !# @Namespace = foo
Opção de exportações
Você pode especificar uma lista de modelos LG para exportar. Os modelos exportados podem ser chamados como funções predefinidas.
O seguinte exemplo mostra como definir a opção de exportações como template1, template2
:
> !# @Namespace = foo
> !# @Exports = template1, template2
# template1(a, b)
- ${a + b}
# template2(a, b)
- ${join(a, b)}
Use foo.template1(1,2), foo.template2(['a', 'b', 'c'], ',')
para chamar esses modelos exportados.
Escopo do cache
As opções de escopo de cache permitem controlar quando o avaliador LG reavalia uma expressão que viu antes e quando armazena e usa um resultado armazenado em cache.
- O cache global é efetivo no ciclo de vida de uma avaliação. A LG armazena em cache todos os resultados da avaliação e, se o nome do modelo e os parâmetros forem os mesmos, retornará o resultado do cache.
- O escopo do cache local é o padrão. Na mesma camada, se o modelo anterior tiver sido chamado com o mesmo nome de modelo e os mesmos parâmetros, o resultado armazenado em cache será retornado diretamente.
- Nenhum escopo de cache desabilita todo o escopo de cache e sempre retorna o novo resultado.
Para obter exemplos, confira os exemplos de escopo de cache global e local.
> !# @cacheScope= global // global cache
> !# @cacheScope= local // local cache
> !# @cacheScope= none // none cache
> !# @cacheScope= xxx // fallback to local cache
Observe que a opção de escopo de cache não diferencia maiúsculas de minúsculas.
> !# @cacheScope= global // ok
> !# @CACHESCOPE= global // ok
> !# @cachescope= global // ok
Observe que o escopo do cache segue o escopo do arquivo .lg do Microsoft Entra.
Digamos que você tenha dois arquivos: a.lg
e b.lg
, mostrados abaixo:
a.lg
> !# @cacheScope= global
[import](b.lg)
b.lg
> !# @cacheScope= none
# template1
- ${template2()} ${template2()}
# template2
- ${rand(1, 10000000)}
Se você executar o código a seguir, notará que template2
usa o resultado armazenado em cache do primeiro resultado avaliado devido à opção global
de escopo de cache em a.lg:
var templates = Templates.ParseFile("a.lg");
var result = templates.Evaluate("template1"); // the second "template2" would use the cache of the first evaluate result
Executar novamente a influência da marca
Se o nome do modelo terminar com "!", o modelo forçará uma nova execução. Esse resultado não será adicionado ao cache, independentemente do escopo do cache.
Digamos que você tenha o seguinte modelo:
# template2
- ${template1()} ${template1!()} ${template1()}
template1!()
é acionado e o resultado é adicionado ao cache. O segundo template1()
fecha o resultado do primeiro template1()
. A chamada final usa os resultados armazenados no cache.
Exemplo de escopo de cache global
Suponha que você tenha os seguintes modelos:
# template1
- ${template2()} ${template3()}
# template2
- ${rand(1, 10)}
- abc
- hi
# template3
- ${template2()}
template2
seria avaliada uma vez, e a segunda execução em template3
aplicaria o cache da primeira.
O snippet de código a seguir é um outro exemplo:
var templates = Templates.ParseFile("xxx.lg");
var result1 = templates.Evaluate("template", null, new EvaluationOptions { CacheScope = LGCacheScope.Global});
// The second evaluation would drop all the results cached before.
var result2 = templates.Evaluate("template", null, new EvaluationOptions { CacheScope = LGCacheScope.Global});
Um modelo é analisado usando a função Templates.ParseFile()
e os resultados da avaliação do modelo são armazenados no result1
. Observe que os resultados da segunda avaliação, result2
, descartam todos os resultados armazenados em cache anteriormente.
Exemplo de escopo de cache local
Os exemplos a seguir mostram quando o escopo de cache local funciona e quando não funciona. Suponha que t()
e subT()
sejam modelos que usam um parâmetro:
> Cache works, the second template call would re-use the first's result.
# template1
- ${t(param)} ${t(param)}
> Cache doesn't work because param1's value is different with param2's. value)
# template2
- ${t(param1)} ${t(param2)}
> Cache doesn't work because of different layers.
# template3
- ${subT(param1)} ${t(param2)}
# subT(param)
- ${t(param)}
Recursos adicionais
- Referência de API C#
- Referência de API JavaScript
- Leia Depurar com Ferramentas Adaptáveis para saber como analisar e depurar arquivos .lg.