You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化MS Bot向Azure Cosmos DB存储对话文本的实现方案?

嘿,很高兴看到你已经成功把MS Bot和Azure Cosmos DB打通了!目前你手动在每个PostAsync方法里调用context.ConversationData.SetValue("message", messageText);来存储对话文本的方式,虽然能实现需求,但确实有点重复冗余。这里有几个更优雅的优化方案,帮你摆脱重复代码:

方案1:用自定义中间件(Middleware)统一拦截消息(适合Bot Framework v3)

中间件可以在消息到达Bot业务逻辑的前后自动处理,刚好可以用来统一记录所有对话消息,不用在每个PostAsync里重复写存储代码。

首先创建一个消息日志中间件类:

public class MessageLoggingMiddleware : IMiddleware
{
    public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default)
    {
        // 只处理用户发送的消息类型
        if (turnContext.Activity.Type == ActivityTypes.Message)
        {
            var messageText = turnContext.Activity.Text;
            
            // 如果你需要保存单条最新消息,用下面的代码
            await turnContext.ConversationData.SetValueAsync("message", messageText, cancellationToken);
            
            // 如果需要保存完整的消息历史(不覆盖旧消息),可以改用列表存储
            // var messageHistory = await turnContext.ConversationData.GetValueOrDefaultAsync<List<string>>("messageHistory", new List<string>(), cancellationToken);
            // messageHistory.Add(messageText);
            // await turnContext.ConversationData.SetValueAsync("messageHistory", messageHistory, cancellationToken);
        }

        // 继续执行后续的Bot业务逻辑
        await next(cancellationToken);
    }
}

然后在你的Global.asax.cs里注册这个中间件:

// 假设你已经实例化了自己的Bot类
var yourBot = new YourCustomBot();
// 添加中间件到Bot的管道中
yourBot.Use(new MessageLoggingMiddleware());

这样所有用户发送的消息都会被自动拦截并存储到Cosmos DB里,完全不用在每个PostAsync里重复写存储逻辑。

方案2:扩展DocumentDbBotDataStore自定义存储逻辑

如果你想直接从底层存储层面做扩展,可以继承默认的DocumentDbBotDataStore,重写SaveAsync方法,在保存Bot数据的时候自动把对话消息加进去:

public class CustomDocumentDbBotDataStore : DocumentDbBotDataStore
{
    public CustomDocumentDbBotDataStore(Uri serviceEndpoint, string authKey) : base(serviceEndpoint, authKey)
    {
    }

    public override async Task SaveAsync(IAddress key, BotData data, CancellationToken cancellationToken = default)
    {
        // 只处理对话范围内的消息
        if (data.BotDataScope == BotDataScope.Conversation && data.Activity != null && data.Activity.Type == ActivityTypes.Message)
        {
            var messageText = data.Activity.Text;
            // 保存最新单条消息
            data.SetValue("message", messageText);
            
            // 或者保存消息历史列表
            // var messageHistory = data.GetValueOrDefault<List<string>>("messageHistory", new List<string>());
            // messageHistory.Add(messageText);
            // data.SetValue("messageHistory", messageHistory);
        }
        
        // 调用父类方法完成最终的Cosmos DB存储
        await base.SaveAsync(key, data, cancellationToken);
    }
}

然后在Global.asax.cs里替换原来的存储实例:

var uri = new Uri(ConfigurationManager.AppSettings["DocumentDbUrl"]);
var key = ConfigurationManager.AppSettings["DocumentDbKey"];
// 用自定义的存储类替换默认的DocumentDbBotDataStore
var store = new CustomDocumentDbBotDataStore(uri, key);
Conversation.UpdateContainer(builder => builder.Register(c => store).As<IBotDataStore<BotData>>().SingleInstance());

这个方案更贴近底层存储逻辑,所有Bot数据保存操作都会自动带上消息文本,无需额外调用SetValue。

方案3:用对话状态管理消息历史(适合Bot Framework v4+)

如果你使用的是较新的Bot Framework v4版本,更推荐使用框架原生的ConversationState来管理对话数据,配合自定义状态类来存储消息历史:

首先定义一个自定义的对话状态类:

public class ConversationMessageHistory
{
    // 用来存储所有对话消息的列表
    public List<string> Messages { get; set; } = new List<string>();
}

然后在你的Bot类中注入ConversationState,并在消息处理逻辑中自动保存消息:

public class YourCustomBot : ActivityHandler
{
    private readonly ConversationState _conversationState;
    private readonly IStatePropertyAccessor<ConversationMessageHistory> _messageHistoryAccessor;

    // 通过构造函数注入ConversationState
    public YourCustomBot(ConversationState conversationState)
    {
        _conversationState = conversationState;
        // 创建状态属性访问器
        _messageHistoryAccessor = _conversationState.CreateProperty<ConversationMessageHistory>("MessageHistory");
    }

    protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
    {
        // 获取当前对话的消息历史
        var messageHistory = await _messageHistoryAccessor.GetAsync(turnContext, () => new ConversationMessageHistory(), cancellationToken);
        // 添加最新的用户消息
        messageHistory.Messages.Add(turnContext.Activity.Text);
        // 保存状态到Cosmos DB
        await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);

        // 这里写你的Bot业务逻辑
        await turnContext.SendActivityAsync($"收到你的消息:{turnContext.Activity.Text}", cancellationToken: cancellationToken);
    }
}

这个方案完全贴合Bot Framework v4的设计模式,状态管理更规范,也能自动完成持久化操作。


根据你当前的实现场景,我更推荐方案1或者方案2;如果是使用v4版本的Bot Framework,方案3会是更合适的选择。这些方案都能帮你省去重复代码,让消息存储逻辑更集中、更易维护。

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:34:45