Teams AI 库简化了使用 AI 组件生成智能Microsoft Teams 应用程序。 它提供用于数据访问、自定义 UI 创建、提示管理和安全审查的 API。 可以使用 OpenAI 或 Azure OpenAI 轻松创建机器人,以提供 AI 驱动的体验。
初始设置
Teams AI 库基于 Bot Framework SDK 构建。 它通过导入核心功能来扩展 Bot Framework 的功能。 作为初始设置的一部分,导入 Bot Framework SDK 组件。 处理与通道连接的适配器类是从 Bot Framework SDK 导入的。
.NET Code:初始配置和适配器设置
using Microsoft.Teams.AI;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.TeamsFx.Conversation;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddHttpClient("WebClient", client => client.Timeout = TimeSpan.FromSeconds(600));
builder.Services.AddHttpContextAccessor();
// Prepare Configuration for ConfigurationBotFrameworkAuthentication
var config = builder.Configuration.Get<ConfigOptions>();
builder.Configuration["MicrosoftAppType"] = "MultiTenant";
builder.Configuration["MicrosoftAppId"] = config.BOT_ID;
builder.Configuration["MicrosoftAppPassword"] = config.BOT_PASSWORD;
// Create the Bot Framework Authentication to be used with the Bot Adapter.
builder.Services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
// Create the Cloud Adapter with error handling enabled.
// Note: some classes expect a BotAdapter and some expect a BotFrameworkHttpAdapter, so
// register the same adapter instance for all types.
builder.Services.AddSingleton<CloudAdapter, AdapterWithErrorHandler>();
builder.Services.AddSingleton<IBotFrameworkHttpAdapter>(sp => sp.GetService<CloudAdapter>());
builder.Services.AddSingleton<BotAdapter>(sp => sp.GetService<CloudAdapter>());
导入 Teams AI 库
从 @microsoft/teams-ai
中导入所有类以生成机器人并使用 Teams AI 库功能。
JavaScript 代码:导入 Teams AI 库
// import Teams AI library
import {
AI,
Application,
ActionPlanner,
OpenAIModerator,
OpenAIModel,
PromptManager,
TurnState
} from '@microsoft/teams-ai';
import { addResponseFormatter } from './responseFormatter';
import { VectraDataSource } from './VectraDataSource';
创建 AI 组件
可以在现有机器人应用或新的 Bot Framework 应用中创建 AI 组件。 main组件包括:
- OpenAIModel:提供对 OpenAI API 或遵循 OpenAI REST 格式的任何服务的访问权限。 它适用于 OpenAI 和 Azure OpenAI 语言模型。
- 提示管理器:管理提示创建。 它将函数、会话状态和用户状态自动插入提示符中。
- ActionPlanner: (LLM) 调用大型语言模型,并包含用于增强和自定义模型的功能。 此组件根据用户输入和可用作生成和执行计划。
.NET Code:创建 AI 组件
// Create model
OpenAIModel? model = null;
if (!string.IsNullOrEmpty(config.OpenAI?.ApiKey))
{
model = new(new OpenAIModelOptions(config.OpenAI.ApiKey, "gpt-3.5-turbo"));
}
else if (!string.IsNullOrEmpty(config.Azure?.OpenAIApiKey) && !string.IsNullOrEmpty(config.Azure.OpenAIEndpoint))
{
model = new(new AzureOpenAIModelOptions(
config.Azure.OpenAIApiKey,
"gpt-35-turbo",
config.Azure.OpenAIEndpoint
));
}
if (model == null)
{
throw new Exception("please configure settings for either OpenAI or Azure");
}
// Create prompt manager
PromptManager prompts = new(new()
{
PromptFolder = "./Prompts",
});
// Add function to be referenced in the prompt template
prompts.AddFunction("getLightStatus", async (context, memory, functions, tokenizer, args) =>
{
bool lightsOn = (bool)(memory.GetValue("conversation.lightsOn") ?? false);
return await Task.FromResult(lightsOn ? "on" : "off");
});
// Create ActionPlanner
ActionPlanner<AppState> planner = new(
options: new(
model: model,
prompts: prompts,
defaultPrompt: async (context, state, planner) =>
{
PromptTemplate template = prompts.GetPrompt("sequence");
return await Task.FromResult(template);
}
)
{ LogRepairs = true },
loggerFactory: loggerFactory
);
定义存储和应用程序
应用程序对象自动管理机器人的聊天和用户状态。 其中包括:
- 存储:存储提供程序存储聊天和用户状态。
-
应用程序:类
Application
为应用注册作或活动处理程序。 它包含所有必要的信息和机器人逻辑。
.NET 代码:定义存储和应用程序
return new TeamsLightBot(new()
{
Storage = sp.GetService<IStorage>(),
AI = new(planner),
LoggerFactory = loggerFactory,
TurnStateFactory = () =>
{
return new AppState();
}
});
属性 TurnStateFactory
允许创建自定义状态类来存储其他信息或逻辑。 通过创建一个类来扩展默认轮次状态,该类包含其他属性 ((例如用户输入、机器人输出或聊天历史记录) ),并将创建类实例的函数传递给应用构造函数。
注册数据源
矢量数据源简化了向任何提示添加 Retrieval-Augmented 代 (RAG) 。 向规划器注册命名数据源,并在提示 config.json
文件中指定它以增加提示。 这允许 AI 将来自外部源 ((例如矢量数据库或认知搜索) )的相关信息注入提示。
JavaScript 代码:向 Planner 注册数据源
// Register your data source with planner
planner.prompts.addDataSource(new VectraDataSource({
name: 'teams-ai',
apiKey: process.env.OPENAI_API_KEY!,
indexFolder: path.join(__dirname, '../index'),
}));
嵌入
嵌入是 LLM 生成的矢量,用于表示文本,捕获其语义含义。 嵌入用于文本分类、情绪分析、搜索等。 例如,OpenAI 的 text-embedding-ada-002
模型返回表示输入文本的 1536 个数字的列表。 这些嵌入存储在矢量数据库中。 在自定义引擎代理中,RAG 模式可以从矢量数据库检索相关数据并增加提示符。
示例:VectraDataSource 和 OpenAIEmbeddings
import { DataSource, Memory, RenderedPromptSection, Tokenizer } from '@microsoft/teams-ai';
import { OpenAIEmbeddings, LocalDocumentIndex } from 'vectra';
import * as path from 'path';
import { TurnContext } from 'botbuilder';
/**
* Options for creating a `VectraDataSource`.
*/
export interface VectraDataSourceOptions {
/**
* Name of the data source and local index.
*/
name: string;
/**
* OpenAI API key to use for generating embeddings.
*/
apiKey: string;
/**
* Path to the folder containing the local index.
* @remarks
* This should be the root folder for all local indexes and the index itself
* needs to be in a subfolder under this folder.
*/
indexFolder: string;
/**
* Optional. Maximum number of documents to return.
* @remarks
* Defaults to `5`.
*/
maxDocuments?: number;
/**
* Optional. Maximum number of chunks to return per document.
* @remarks
* Defaults to `50`.
*/
maxChunks?: number;
/**
* Optional. Maximum number of tokens to return per document.
* @remarks
* Defaults to `600`.
*/
maxTokensPerDocument?: number;
}
/**
* A data source that uses a local Vectra index to inject text snippets into a prompt.
*/
export class VectraDataSource implements DataSource {
private readonly _options: VectraDataSourceOptions;
private readonly _index: LocalDocumentIndex;
/**
* Name of the data source.
* @remarks
* This is also the name of the local Vectra index.
*/
public readonly name: string;
/**
* Creates a new `VectraDataSource` instance.
* @param options Options for creating the data source.
*/
public constructor(options: VectraDataSourceOptions) {
this._options = options;
this.name = options.name;
// Create embeddings model
const embeddings = new OpenAIEmbeddings({
model: 'text-embedding-ada-002',
apiKey: options.apiKey,
});
// Create local index
this._index = new LocalDocumentIndex({
embeddings,
folderPath: path.join(options.indexFolder, options.name),
});
}
/**
* Renders the data source as a string of text.
* @param context Turn context for the current turn of conversation with the user.
* @param memory An interface for accessing state values.
* @param tokenizer Tokenizer to use when rendering the data source.
* @param maxTokens Maximum number of tokens allowed to be rendered.
*/
public async renderData(context: TurnContext, memory: Memory, tokenizer: Tokenizer, maxTokens: number): Promise<RenderedPromptSection<string>> {
// Query index
const query = memory.getValue('temp.input') as string;
const results = await this._index.queryDocuments(query, {
maxDocuments: this._options.maxDocuments ?? 5,
maxChunks: this._options.maxChunks ?? 50,
});
// Add documents until you run out of tokens
let length = 0;
let output = '';
let connector = '';
for (const result of results) {
// Start a new doc
let doc = `${connector}url: ${result.uri}\n`;
let docLength = tokenizer.encode(doc).length;
const remainingTokens = maxTokens - (length + docLength);
if (remainingTokens <= 0) {
break;
}
// Render document section
const sections = await result.renderSections(Math.min(remainingTokens, this._options.maxTokensPerDocument ?? 600), 1);
docLength += sections[0].tokenCount;
doc += sections[0].text;
// Append doc to output
output += doc;
length += docLength;
connector = '\n\n';
}
return { output, length, tooLong: length > maxTokens };
}
}
提示
提示是用于创建对话体验的文本段,例如启动对话、提问和生成响应。 新的基于对象的提示系统将提示划分为多个部分,每个部分都有自己的令牌预算 (固定或成比例的剩余令牌) 。 可以为文本完成和聊天完成样式 API 生成提示。
按照以下准则创建有效提示:
- 提供明确的说明和示例。
- 确保具有足够示例的高质量校对数据。
- 使用
temperature
和top_p
调整提示设置,以控制模型的输出。 更高的值 (例如,0.8) 产生随机输出;较低的值 (例如,0.2) 创建集中的确定性响应。
若要实现提示,请执行以下命令:
- 创建名为 的文件夹
prompts
。 - 在专用文件中定义提示模板和设置:
-
skprompt.txt
:包含支持模板变量和函数的提示文本。 -
config.json
:包含提示模型设置,确保机器人的响应满足你的要求。
-
示例: config.json
对于“提示设置”
{
"schema": 1.1,
"description": "A bot that can turn the lights on and off",
"type": "completion",
"completion": {
"model": "gpt-3.5-turbo",
"completion_type": "chat",
"include_history": true,
"include_input": true,
"max_input_tokens": 2800,
"max_tokens": 1000,
"temperature": 0.2,
"top_p": 0.0,
"presence_penalty": 0.6,
"frequency_penalty": 0.0,
"stop_sequences": []
},
"augmentation": {
"augmentation_type": "sequence"
"data_sources": {
"teams-ai": 1200
}
}
}
查询参数
下表详细介绍了查询参数:
值 | 说明 |
---|---|
model |
要使用的模型的 ID。 |
completion_type |
要使用的完成类型。 该模型返回一个或多个预测完成和替代令牌的概率。 支持的选项: chat 和 text 。 默认值:chat 。 |
include_history |
Boolean 值。 指示是否包含历史记录。 每个提示都会获取自己的对话历史记录,以避免混淆。 |
include_input |
Boolean 值。 如果设置为 true,则提示中包含用户的输入。 |
max_input_tokens |
允许输入的最大令牌数。 (支持的最大令牌数:4000) |
max_tokens |
要生成的令牌的最大数目。 提示标记和 的总和 max_tokens 不能超过模型的上下文长度。 |
temperature |
采样温度 (范围:0 到 2) 。 更高的值 (例如,0.8) 产生更多的随机输出;较低的值 (例如,0.2) 生成焦点输出。 |
top_p |
温度采样的替代方法,称为核采样。 例如,值 0.1 表示仅考虑概率质量前 10% 的令牌。 |
presence_penalty |
介于 -2.0 和 2.0 之间的数字。 正值根据新令牌是否出现在文本中来惩罚新令牌,从而鼓励讨论新主题。 |
frequency_penalty |
介于 -2.0 和 2.0 之间的数字。 正值根据令牌的频率惩罚令牌,从而降低重复的可能性。 |
stop_sequences |
API 停止生成令牌的最多四个序列。 返回的文本不包括停止序列。 |
augmentation_type |
扩充的类型。 支持的值为 sequence 、 monologue 和 tools 。 |
提示管理
提示管理根据令牌预算和可用数据源动态调整提示大小和内容。 例如,对于具有 4,000 个令牌限制的机器人 (输入限制为 2,800,输出限制为 1,000) ,该模型为来自外部源的聊天历史记录、输入和任何扩充数据保留令牌。
提示作
提示作允许模型执行作或响应用户输入。 可以使用相应的参数创建一个架构,列出支持的作。 OpenAI 终结点提取实体并将其作为参数传递给作处理程序。
例如:
The following is a conversation with an AI assistant.
The assistant can turn a light on or off.
context:
The lights are currently {{getLightStatus}}.
提示模板
提示模板使用纯文本定义和撰写 AI 函数。 它允许你:
- 创建自然语言提示。
- 生成响应。
- 提取信息。
- 调用其他提示。
该语言支持使用大括号 {{...}}
嵌入变量和函数。 一些关键表达式包括:
-
{{function}}
:调用已注册的函数并插入其返回值。 -
{{$input}}
:插入从state.temp.input
获取的用户消息文本。 -
{{$state.[property]}}
:插入状态属性。
操作
作处理由 AI 组件触发的事件。 内置 FlaggedInputAction
和 FlaggedOutputAction
句柄审查器标志。 标记消息时,机器人会通过 context.sendActivity
通知用户。 若要停止作,请返回 AI.StopCommandName
。
JavaScript 代码:注册已标记的输入和输出作
// Register other AI actions
app.ai.action(
AI.FlaggedInputActionName,
async (context: TurnContext, state: ApplicationTurnState, data: Record<string, any>) => {
await context.sendActivity(`I'm sorry your message was flagged: ${JSON.stringify(data)}`);
return AI.StopCommandName;
}
);
app.ai.action(AI.FlaggedOutputActionName, async (context: TurnContext, state: ApplicationTurnState, data: any) => {
await context.sendActivity(`I'm not allowed to talk about such things.`);
return AI.StopCommandName;
});
注册作处理程序
作处理程序可帮助机器人执行特定任务。 首先,在提示符中注册作,然后为每个作实现处理程序,包括未知作。
在以下轻型机器人示例中,作包括 LightsOn
、 LightsOff
和 Pause
。 每个作处理程序返回一个 string
。 对于返回时间 (例如暂停持续时间) 的作, PauseParameters
属性可确保时间采用数字格式。
.NET 代码:LightBot 的作处理程序
public class LightBotActions
{
[Action("LightsOn")]
public async Task<string> LightsOn([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] AppState turnState)
{
turnState.Conversation!.LightsOn = true;
await turnContext.SendActivityAsync(MessageFactory.Text("[lights on]"));
return "the lights are now on";
}
[Action("LightsOff")]
public async Task<string> LightsOff([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] AppState turnState)
{
turnState.Conversation!.LightsOn = false;
await turnContext.SendActivityAsync(MessageFactory.Text("[lights off]"));
return "the lights are now off";
}
[Action("Pause")]
public async Task<string> LightsOff([ActionTurnContext] ITurnContext turnContext, [ActionParameters] Dictionary<string, object> args)
{
// Try to parse entities returned by the model.
// Expecting "time" to be a number of milliseconds to pause.
if (args.TryGetValue("time", out object? time))
{
if (time != null && time is string timeString)
{
if (int.TryParse(timeString, out int timeInt))
{
await turnContext.SendActivityAsync(MessageFactory.Text($"[pausing for {timeInt / 1000} seconds]"));
await Task.Delay(timeInt);
}
}
}
return "done pausing";
}
[Action("LightStatus")]
public async Task<string> LightStatus([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] AppState turnState)
{
await turnContext.SendActivityAsync(ResponseGenerator.LightStatus(turnState.Conversation!.LightsOn));
return turnState.Conversation!.LightsOn ? "the lights are on" : "the lights are off";
}
[Action(AIConstants.UnknownActionName)]
public async Task<string> UnknownAction([ActionTurnContext] TurnContext turnContext, [ActionName] string action)
{
await turnContext.SendActivityAsync(ResponseGenerator.UnknownAction(action ?? "Unknown"));
return "unknown action";
}
}
}
使用序列、独白或工具扩充可防止模型产生无效函数名称、作名称或参数的幻觉。 创建作文件以:
- 定义用于提示扩充的作。
- 指示何时执行作。
例如,在轻型机器人中 actions.json
,该文件可能会列出如下所示的作:
[
{
"name": "LightsOn",
"description": "Turns on the lights"
},
{
"name": "LightsOff",
"description": "Turns off the lights"
},
{
"name": "Pause",
"description": "Delays for a period of time",
"parameters": {
"type": "object",
"properties": {
"time": {
"type": "number",
"description": "The amount of time to delay in milliseconds"
}
},
"required": [
"time"
]
}
}
]
-
name
:需要) (作的名称。 -
description
:可选) (作的说明。 -
parameters
:定义所需参数的 JSON 架构。
反馈循环有助于验证、更正和优化机器人的交互。 对于 sequence
扩充,请在实现中将 设置为 allow_looping?
false
或 AIOptions
将 max_repair_attempts
0
设置为 来禁用循环。
管理历史记录
MaxHistoryMessages
使用 和 MaxConversationHistoryTokens
设置允许 AI 库自动管理对话历史记录。
反馈循环
反馈循环监视和改进机器人交互。 其中包括:
- 修复Loop:当响应不足以尝试备用解决方案时,创建对话历史记录分支。
- 验证:验证更正的响应,然后再将其合并回对话。
- 学习:根据正确的行为示例调整机器人的性能。
- 复杂命令处理:增强模型随时间推移处理复杂命令的能力。
将传统机器人升级到自定义引擎代理
如果 Teams 上已有机器人,则可以将其升级到支持流式处理、引文和 AI 标签的自定义引擎代理。 此升级使机器人与对话式 AI UX 范例保持一致,并提供声明性代理的一致体验。
注意
Python 不支持自定义引擎代理。
升级步骤:
To-Do 列表 | 支持文档 |
---|---|
更新 AI SDK 版本 | • 对于 JavaScript,请更新到 v1.6.1。 • 对于 C#,请更新到 v1.8.1。 |
为机器人启用流式处理。 | Stream机器人消息 |
使用 AI 标签指示 AI 生成的消息。 | AI 标签 |
对源引用使用引文。 | 引文 |
添加对智能 Microsoft 365 Copilot 副驾驶® 对话助手的支持
可以在 智能 Microsoft 365 Copilot 副驾驶® 对话助手 中添加对自定义引擎代理的支持。 这包括对异步模式的支持,例如后续消息和长时间运行的任务。 有关详细信息,请参阅 异步模式。
若要支持智能 Microsoft 365 Copilot 副驾驶® 对话助手,请更新应用清单:
将
copilotAgents
具有子属性的属性customEngineAgents
添加到 应用清单:"copilotAgents": { "customEngineAgents": [ { "type": "bot", "id": "<Bot-Id-Guid>" } ] }
scopes
personal
在应用清单中将bots
和commandLists
设置为 :"bots": [ { "botId": "<Bot-Id-Guid>", "scopes": [ "personal", "team", "groupChat" ], "commandLists": [ { "scopes": ["personal"], "commands": [ { "title": "Sample prompt title", "description": "Description of sample prompt" } ] }, { "scopes": ["personal"], "commands": [ { "title": "Sample prompt title", "description": "Description of sample prompt" } ] } ], } ],
注意
- 智能 Microsoft 365 Copilot 副驾驶® 对话助手将 AI 生成的标签添加到每个自定义引擎代理响应。
- 对于使用 Microsoft 365 Agents Toolkit (以前是 Teams 工具包) 构建 智能 Microsoft 365 Copilot 副驾驶® 对话助手的机器人,请遵循分步指南。
- 自定义引擎代理的单一登录 (SSO) 可用,但 Outlook 客户端不支持。 请参阅更新 sso Microsoft Entra应用注册。
提升传统机器人以使用 AI
可以将现有传统机器人更新为 AI 提供支持。 添加 AI 层可增强机器人的 LLM 驱动功能。 下面是使用 Bot Framework 适配器和 对象集成 AI 层的示例 app
。
JavaScript 代码:提升传统机器人以使用 AI
// Create AI components
const model = new OpenAIModel({
// OpenAI Support
apiKey: process.env.OPENAI_KEY!,
defaultModel: 'gpt-4o',
// Azure OpenAI Support
azureApiKey: process.env.AZURE_OPENAI_KEY!,
azureDefaultDeployment: 'gpt-4o',
azureEndpoint: process.env.AZURE_OPENAI_ENDPOINT!,
azureApiVersion: '2023-03-15-preview',
// Request logging
logRequests: true
});
const prompts = new PromptManager({
promptsFolder: path.join(__dirname, '../src/prompts')
});
// Define a prompt function for getting the current status of the lights
prompts.addFunction('getLightStatus', async (context: TurnContext, memory: Memory) => {
return memory.getValue('conversation.lightsOn') ? 'on' : 'off';
});
const planner = new ActionPlanner({
model,
prompts,
defaultPrompt: 'tools'
});
// Define storage and application
const storage = new MemoryStorage();
const app = new Application<ApplicationTurnState>({
storage,
ai: {
planner
}
});
app.ai.action('LightStatus', async (context: TurnContext, state: ApplicationTurnState) => {
const status = state.conversation.lightsOn ? 'on' : 'off';
return `the lights are ${status}`;
});
// Register action handlers
app.ai.action('LightsOn', async (context: TurnContext, state: ApplicationTurnState) => {
state.conversation.lightsOn = true;
await context.sendActivity(`[lights on]`);
return `the lights are now on`;
});
app.ai.action('LightsOff', async (context: TurnContext, state: ApplicationTurnState) => {
state.conversation.lightsOn = false;
await context.sendActivity(`[lights off]`);
return `the lights are now off`;
});
interface PauseParameters {
time: number;
}
app.ai.action('Pause', async (context: TurnContext, state: ApplicationTurnState, parameters: PauseParameters) => {
await context.sendActivity(`[pausing for ${parameters.time / 1000} seconds]`);
await new Promise((resolve) => setTimeout(resolve, parameters.time));
return `done pausing`;
});
// Listen for incoming server requests.
server.post('/api/messages', async (req, res) => {
// Route received a request to adapter for processing
await adapter.process(req, res as any, async (context) => {
// Dispatch to application for routing
await app.run(context);
});
});
迁移机器人以使用 Teams AI 库
如果使用 Bot Framework SDK 构建机器人,则可以迁移到 Teams AI 库来解锁高级 AI 功能。 迁移具有以下优势:
- 用于构建由 LLM 提供支持的复杂 Teams 应用程序的高级 AI 系统。
- 用于访问第三方用户数据的集成用户身份验证。
- 利用熟悉的 Bot Framework SDK 工具和概念。
- 支持最新的 LLM 工具和 API。
选择机器人语言的相关迁移指南:
迁移 Bot Framework SDK 应用... | 若要使用 Teams AI 库... |
---|---|
使用 JavaScript 生成的机器人应用 | 迁移 |
使用 C 生成的机器人应用# | 迁移 |
使用 Python 的机器人应用 | 迁移 |
代码示例
示例名称 | 说明 | .NET | Node.js |
---|---|---|---|
作映射 lightbot | 演示 LightBot 如何理解用户意图并根据命令控制轻型机器人。 | View | View |
后续步骤
如果要尝试使用代理工具包和 Teams AI 库创建基于方案的自定义引擎代理,请选择以下选项:
高级分步指南
若要了解 Teams AI 库的核心功能,请选择以下项:
了解 Teams AI 库