Skip to main content

Best Practices

When sending messages using AI, Teams recommends a number of best practices to help with both user and developer experience.

AI-Generated Indicatorโ€‹

When sending messages using AI, Teams recommends including an indicator that the message was generated by AI. This can be done by setting the ChannelData property on outgoing messages. This will help users understand that the message was generated by AI, and not by a human and can help with trust and transparency.

using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Apps;
using Microsoft.Teams.Apps.Activities;
using Microsoft.Teams.Apps.Annotations;

[TeamsController]
public class Controller(OpenAIChatPrompt _prompt)
{
[Message]
public async Task OnMessage(IContext<MessageActivity> context)
{
var state = State.From(context);

// Send AI-generated response with streaming
await _prompt.Send(context.Activity.Text, new() { Messages = state.Messages }, (chunk) => Task.Run(() =>
{
// Stream chunks with AI indicator
context.Stream.Emit(chunk);
}), context.CancellationToken);

state.Save(context);
}
}

AI Generated Indicator

Gather feedback to improve promptsโ€‹

AI Generated messages are not always perfect. Prompts can have gaps, and can sometimes lead to unexpected results. To help improve the prompts, Teams recommends gathering feedback from users on the AI-generated messages. See Feedback for more information on how to gather feedback.

This does involve thinking through a pipeline for gathering feedback and then automatically, or manually, updating prompts based on the feedback. The feedback system is an point of entry to your eval pipeline.

State Managementโ€‹

Proper state management is crucial for maintaining conversation context across multiple interactions. The Samples.Lights project demonstrates a clean pattern for managing conversation state:

using Microsoft.Teams.AI;
using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Apps;

public class State
{
public bool Status = false;
public IList<IMessage> Messages = [];

public static State From(IContext<IActivity> context)
{
return From<IActivity>(context);
}

public static State From<TActivity>(IContext<TActivity> context) where TActivity : IActivity
{
var key = $"{context.Activity.Conversation.Id}.{context.Activity.From.Id}";
return (State?)context.Storage.Get(key) ?? new();
}

public void Save(IContext<IActivity> context)
{
Save<IActivity>(context);
}

public void Save<TActivity>(IContext<TActivity> context) where TActivity : IActivity
{
var key = $"{context.Activity.Conversation.Id}.{context.Activity.From.Id}";
context.Storage.Set(key, this);
}
}

Function Callingโ€‹

AI function calling allows your application to provide structured capabilities to the AI model. Here's how to implement functions using the modern Teams AI framework:

using Microsoft.Teams.AI.Annotations;
using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Apps;

[Prompt]
[Prompt.Description("manage light status")]
[Prompt.Instructions(
"The following is a conversation with an AI assistant.",
"The assistant can turn the lights on or off.",
"The lights are currently off."
)]
public class LightsPrompt(IContext.Accessor accessor)
{
private IContext<IActivity> context => accessor.Value!;

[Function]
[Function.Description("get the current light status")]
public bool GetLightStatus()
{
return State.From(context).Status;
}

[Function]
[Function.Description("turn the lights on")]
public string LightsOn()
{
var state = State.From(context);
state.Status = true;
state.Save(context);
return "the lights are now on";
}

[Function]
[Function.Description("turn the lights off")]
public string LightsOff()
{
var state = State.From(context);
state.Status = false;
state.Save(context);
return "the lights are now off";
}
}

Application Setupโ€‹

Here's how to properly configure a Teams AI application using modern ASP.NET Core patterns:

using Microsoft.Teams.AI.Models.OpenAI.Extensions;
using Microsoft.Teams.Apps.Extensions;
using Microsoft.Teams.Plugins.AspNetCore.DevTools.Extensions;
using Microsoft.Teams.Plugins.AspNetCore.Extensions;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<Controller>();
builder.AddTeams().AddTeamsDevTools().AddOpenAI<LightsPrompt>();

var app = builder.Build();

app.UseTeams();
app.Run();

Command Handlingโ€‹

Teams AI applications often need to handle specific commands alongside general AI interactions. Here's how to implement command handling using the modern Teams framework:

using System.Text.Json;
using Microsoft.Teams.AI.Models.OpenAI;
using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Apps;
using Microsoft.Teams.Apps.Activities;
using Microsoft.Teams.Apps.Annotations;

[TeamsController]
public class Controller(OpenAIChatPrompt _prompt)
{
[Message("/history")]
public async Task OnHistory(IContext<MessageActivity> context)
{
var state = State.From(context);
await context.Send(JsonSerializer.Serialize(state.Messages, new JsonSerializerOptions()
{
WriteIndented = true
}));
}

[Message]
public async Task OnMessage(IContext<MessageActivity> context)
{
var state = State.From(context);

await _prompt.Send(context.Activity.Text, new() { Messages = state.Messages }, (chunk) => Task.Run(() =>
{
context.Stream.Emit(chunk);
}), context.CancellationToken);

state.Save(context);
}
}

Citationsโ€‹

AI generated messages can hallucinate even if messages are grounded in real data. To help with this, Teams recommends including citations in the AI Generated messages. When using the modern Teams AI framework, citations can be integrated through your prompt design and response formatting.

warning

Citations are added with a position property. This property value needs to also be included in the message text as [<position>]. If there is a citation that's added without the associated value in the message text, Teams will not render the citation

using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Apps;

[TeamsController]
public class ResearchController(ResearchPrompt _prompt)
{
[Message]
public async Task OnMessage(IContext<MessageActivity> context)
{
var state = State.From(context);

// The AI prompt can be instructed to include citations in responses
await _prompt.Send(context.Activity.Text, new()
{
Messages = state.Messages,
Instructions = "Include citations in your response using [1], [2] format for any factual claims."
}, (chunk) => Task.Run(() =>
{
context.Stream.Emit(chunk);
}), context.CancellationToken);

state.Save(context);
}
}

// Example function that provides citation data
[Function]
[Function.Description("Get research citations for a topic")]
public string GetCitations(string topic)
{
// Return structured citation data that the AI can use
return @"Available citations:
[1] Climate Science Research 2023 - https://example.com/climate
[2] IPCC Assessment Report - https://ipcc.ch/reports
Include these in your response when referencing climate data.";
}

AI Generated Indicator