在NiceGUI中集成AutoGen并捕获Agent响应的教程

在NiceGUI中集成AutoGen并捕获Agent响应的教程

本教程旨在解决在nicegui应用中集成autogen时,如何实时捕获并显示agent对话响应的问题。通过深入解析autogen的`register_reply`机制,我们将展示如何注册自定义回调函数来拦截并处理agent的每一条消息,从而将autogen的强大对话能力无缝桥接到nicegui的交互式聊天界面中,确保所有对话内容都能在前端准确呈现。

1. 引言:AutoGen与NiceGUI的融合挑战

在构建基于大型语言模型(LLM)的交互式应用时,我们经常需要结合强大的LLM编排框架(如AutoGen)与灵活的Web UI框架(如NiceGUI)。AutoGen以其多Agent协作能力著称,能够模拟复杂的对话和任务执行流程。然而,当我们将AutoGen集成到NiceGUI等Web界面时,一个常见的问题是如何将AutoGen Agent在后台产生的实时对话内容准确、及时地呈现在用户界面上。AutoGen的initiate_chat方法通常会返回一个包含最终对话结果的对象,但它并不直接提供一个简单的方式来获取对话过程中Agent的每一步回复,而这些中间步骤对于构建流畅的用户体验至关重要。

2. AutoGen与NiceGUI基础设置

首先,我们来看一下AutoGen Agent和NiceGUI界面的基本配置。以下代码展示了如何初始化AutoGen Agent以及一个简单的NiceGUI聊天界面结构。

import autogenfrom nicegui import ui, contextfrom uuid import uuid4# 1. AutoGen 配置config_list = [    {        'model': 'gpt-4',        'api_key': 'YOUR_API_KEY' # 请替换为您的实际API密钥    }]llm_config = {    'seed': 42,    'config_list': config_list,    'temperature': 0.2}# 2. 初始化AutoGen Agentassistant = autogen.AssistantAgent(name='Albert', llm_config=llm_config)user_proxy = autogen.UserProxyAgent(    name='user_proxy',    human_input_mode="NEVER", # 在NiceGUI中,用户输入通过UI提供,Agent无需直接请求    max_consecutive_auto_reply=10, # 允许更多轮次自动回复    is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),    code_execution_config={"work_dir": "web"}, # 设定代码执行的工作目录    llm_config=llm_config)# 3. NiceGUI 界面定义@ui.page('/')def main():    # 存储聊天消息的列表,用于UI显示    messages = []    user_id = str(uuid4()) # 为每个用户会话生成唯一ID    @ui.refreshable    def chat_messages():        """刷新聊天消息显示区域"""        for name, text in messages:            ui.chat_message(text=text, name=name, sent=name == 'You')        if context.get_client().has_socket_connection:            # 自动滚动到底部            ui.run_javascript('setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 0)')    # ... (发送消息的逻辑将在后面修改)    # ... (UI布局)

在上述代码中,我们配置了AssistantAgent和UserProxyAgent。UserProxyAgent的human_input_mode设置为”NEVER”,因为用户输入将通过NiceGUI的文本框提供。NiceGUI部分则定义了一个messages列表来存储对话历史,并通过@ui.refreshable装饰器实现消息的动态更新和滚动。

3. 核心挑战:捕获Agent的实时响应

最初的尝试可能是在send函数中调用user_proxy.initiate_chat后,尝试从其返回值中提取Agent的响应。然而,initiate_chat返回的是一个ChatResult对象,其中包含了整个对话的概要和最终状态,但并不直接提供Agent在对话过程中每一步的详细回复内容。这意味着,如果Agent进行了多轮思考或与UserProxyAgent进行了多次交互,这些中间过程将不会被NiceGUI捕获并显示,用户只能看到最终结果,这严重影响了用户体验。

例如,原始代码中尝试这样获取响应:

# 原始的尝试response = await user_proxy.initiate_chat(assistant, message=user_message)if response and 'content' in response[0]: # 这里的response[0]通常是最后一条消息    assistant_response = response[0]['content']    messages.append(('Albert', assistant_response))

这种方法只能捕获到initiate_chat结束后,对话中最后一条消息的内容,无法实时跟踪整个对话流程。

4. 解决方案:利用register_reply机制

AutoGen提供了一个强大的回调机制——register_reply,它允许我们在Agent发送或接收消息时注册一个自定义函数。这个函数会在每次消息交换时被调用,从而使我们能够实时捕获并处理Agent的对话内容。

Lifetoon Lifetoon

免费的AI漫画创作平台

Lifetoon 92 查看详情 Lifetoon

4.1 register_reply的工作原理

register_reply方法允许你为Agent注册一个或多个回调函数。每当Agent准备发送回复或接收到消息时,这些回调函数就会被触发。其基本签名如下:

agent.register_reply(    trigger: Union[Type[Agent], Agent, List[Union[Type[Agent], Agent]], None],    reply_func: Callable,    config: Optional[Any] = None,    reset_config: Optional[Callable] = None,    position: Optional[int] = None)

其中:

trigger: 指定何时触发回调。可以是一个Agent实例、Agent类型、Agent列表,或者None(表示对所有消息都触发)。reply_func: 这是一个可调用对象(函数),它将在消息交换时被执行。它的签名通常是 (recipient, messages, sender, config)。recipient: 接收当前消息的Agent。messages: 一个列表,包含当前对话回合中所有的消息(通常是最新消息)。sender: 发送当前消息的Agent。config: 注册时传递的配置字典。reply_func的返回值:回调函数需要返回一个元组 (bool, Optional[str])。True表示回调函数已经处理了回复,Agent无需再生成回复。False表示Agent应继续其默认的回复生成逻辑。Optional[str]是回调函数生成的回复内容,如果返回True,则此内容将作为Agent的回复。

4.2 关键回调函数设计

为了将Agent的实时消息显示在NiceGUI界面上,我们需要设计一个回调函数,它能够从messages参数中提取出最新的消息内容和发送者,然后将其添加到NiceGUI的messages列表中,并触发UI刷新。

# 定义一个辅助函数来更新UI消息列表并刷新def append_and_refresh_ui_messages(sender_name: str, content: str):    """将消息添加到UI列表并刷新NiceGUI界面"""    messages.append((sender_name, content))    chat_messages.refresh()# AutoGen回调函数def autogen_reply_callback(recipient, current_messages, sender, config):    """    AutoGen Agent消息回调函数,用于捕获Agent的实时回复。    """    # current_messages 是一个列表,包含当前回合的所有消息。    # 最后一条消息是刚刚发送或接收的消息。    if current_messages:        last_message = current_messages[-1]        sender_name = last_message.get('name', sender.name) # 优先使用消息中的name,否则使用sender的name        content = last_message.get('content', '')        if content:            # 使用NiceGUI的run_sync将UI更新操作调度到主线程            ui.run_sync(lambda: append_and_refresh_ui_messages(sender_name, content))    # 返回 False, None 表示Agent应继续其默认的回复生成逻辑    return False, None

注意: 由于AutoGen的Agent对话可能在后台线程中进行,而NiceGUI的UI更新必须在主线程执行,因此我们使用ui.run_sync来安全地调度append_and_refresh_ui_messages函数。

4.3 注册回调函数

现在,我们将这个回调函数注册到assistant和user_proxy这两个Agent上。这样,无论是assistant回复user_proxy,还是user_proxy向assistant发送消息,我们都能捕获到。

# 在 main() 函数内部,在 Agent 初始化之后,NiceGUI UI定义之前# 注册回调函数assistant.register_reply(    [autogen.Agent, None], # 捕获assistant发送给任何Agent的消息    reply_func=autogen_reply_callback,    config={"callback": None},)user_proxy.register_reply(    [autogen.Agent, None], # 捕获user_proxy发送给任何Agent的消息    reply_func=autogen_reply_callback,    config={"callback": None},)

5. 整合到NiceGUI聊天界面

将register_reply回调机制整合到NiceGUI的main函数中,并调整send函数。现在,send函数只需要负责接收用户输入并启动AutoGen对话,具体的Agent回复将由autogen_reply_callback处理。

import autogenfrom nicegui import ui, contextfrom uuid import uuid4# AutoGen Configurationconfig_list = [    {        'model': 'gpt-4',        'api_key': 'YOUR_API_KEY' # 替换为您的实际API密钥    }]llm_config = {    'seed': 42,    'config_list': config_list,    'temperature': 0.2}# Initialize AutoGen Agents (在 main() 外部初始化,以便在回调中访问)assistant = autogen.AssistantAgent(name='Albert', llm_config=llm_config)user_proxy = autogen.UserProxyAgent(    name='user_proxy',    human_input_mode="NEVER",    max_consecutive_auto_reply=10,    is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),    code_execution_config={"work_dir": "web"},    llm_config=llm_config)@ui.page('/')def main():    messages = [] # 存储聊天消息的列表    user_id = str(uuid4())    @ui.refreshable    def chat_messages():        for name, text in messages:            ui.chat_message(text=text, name=name, sent=name == 'You')        if context.get_client().has_socket_connection:            ui.run_javascript('setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 0)')    # 定义辅助函数和回调函数,它们需要访问到 main() 作用域内的 messages 和 chat_messages    def append_and_refresh_ui_messages(sender_name: str, content: str):        messages.append((sender_name, content))        chat_messages.refresh()    def autogen_reply_callback(recipient, current_messages, sender, config):        if current_messages:            last_message = current_messages[-1]            sender_name = last_message.get('name', sender.name)            content = last_message.get('content', '')            if content:                ui.run_sync(lambda: append_and_refresh_ui_messages(sender_name, content))        return False, None    # 注册回调函数    assistant.register_reply(        [autogen.Agent, None],        reply_func=autogen_reply_callback,        config={"callback": None},    )    user_proxy.register_reply(        [autogen.Agent, None],        reply_func=autogen_reply_callback,        config={"callback": None},    )    async def send():        user_message = task_input.value        if not user_message.strip():            return # 防止发送空消息        # 用户自己的消息直接添加到UI列表        append_and_refresh_ui_messages('You', user_message)        task_input.value = '' # 清空输入框        try:            # 启动AutoGen对话,Agent的回复将通过回调函数处理            await user_proxy.initiate_chat(assistant, message=user_message)        except Exception as e:            # 异常处理,显示错误信息            ui.run_sync(lambda: append_and_refresh_ui_messages('Albert', f"Error: {e}"))        finally:            # 确保在对话结束后刷新UI(虽然回调已经刷新,但以防万一)            ui.run_sync(chat_messages.refresh)    with ui.scroll_area().classes('w-full h-60 p-3 bg-white overflow-auto'):        chat_messages()    with ui.footer().style('position: fixed; left: 0; bottom: 0; width: 100%; background: white; padding: 10px; box-shadow: 0 -2px 5px rgba(0,0,0,0.1);'):        task_input = ui.input().style('width: calc(100% - 100px);').on('keydown.enter', send) # 支持回车发送        ui.button('Send', on_click=send).style('width: 90px;')ui.run(title='Chat with Albert')

6. 注意事项与最佳实践

Agent初始化位置:将AutoGen Agent的初始化放在ui.page装饰的main()函数外部,可以确保Agent实例在整个应用生命周期中只被创建一次,并能在main()函数内部的回调中被访问。回调函数的线程安全:由于AutoGen Agent的运行可能涉及多线程,而NiceGUI的UI更新必须在主线程进行,因此使用ui.run_sync()是至关重要的。它确保了对messages列表和chat_messages.refresh()的调用是在NiceGUI的主事件循环中安全执行的。reply_func的返回值:在我们的场景中,回调函数仅用于监听和显示消息,不应干预Agent的默认回复逻辑,因此返回False, None是正确的选择。如果需要自定义Agent的回复行为,可以返回True和一个字符串作为新的回复。max_consecutive_auto_reply:为了让Agent能够进行多轮次的自主对话,将UserProxyAgent的max_consecutive_auto_reply设置为一个较大的值(例如10),可以避免对话过早终止。错误处理:在send函数中使用try…except块来捕获initiate_chat可能抛出的异常,并将错误信息显示在UI上,提升用户体验。消息来源识别:在autogen_reply_callback中,last_message.get(‘name’, sender.name)能够更准确地识别消息的发送者,因为有时消息字典中会包含name字段,它可能比sender.name更具描述性。终止消息:is_termination_msg参数对于控制Agent何时停止对话至关重要。确保您的Agent在完成任务后发送一个符合终止条件的字符串(例如TERMINATE)。

7.

以上就是在NiceGUI中集成AutoGen并捕获Agent响应的教程的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/904779.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月28日 22:23:18
下一篇 2025年11月28日 22:23:39

相关推荐

  • MyBatis 中 XML 映射文件无法调用的问题排查与解决

    本文旨在帮助开发者解决在使用 Spring Boot 和 MyBatis 框架时,XML 映射文件中定义的 SQL 语句无法被正确调用的问题。文章将通过分析常见原因、提供解决方案以及代码示例,帮助读者快速定位并解决类似问题,确保 MyBatis 能够正确加载和执行 XML 映射文件中的 SQL 语句…

    2025年12月5日
    500
  • win10关闭自动更新 四种禁止更新方法分享

    windows 10系统内置了自动更新机制,虽然有助于保持系统安全与稳定,但对不少用户来说,频繁的更新提示、计划外的重启甚至强制重启严重影响了使用体验。尤其是在进行重要工作或沉浸式游戏时,突如其来的系统更新极易打断操作流程。那么,如何有效关闭win10的自动更新呢?本文将介绍四种实用、安全且可逆的方…

    2025年12月5日 电脑教程
    600
  • HiDream-I1— 智象未来开源的文生图模型

    hidream-i1:一款强大的开源图像生成模型 HiDream-I1是由HiDream.ai团队开发的17亿参数开源图像生成模型,采用MIT许可证,在图像质量和对提示词的理解方面表现卓越。它支持多种风格,包括写实、卡通和艺术风格,广泛应用于艺术创作、商业设计、科研教育以及娱乐媒体等领域。 HiDr…

    2025年12月5日
    000
  • 如何在Laravel中集成支付网关

    在laravel中集成支付网关的核心步骤包括:1.根据业务需求选择合适的支付网关,如stripe、paypal或支付宝等;2.通过composer安装对应的sdk或laravel包,如stripe/stripe-php或yansongda/pay;3.在.env文件和config/services.…

    2025年12月5日
    300
  • Java中死锁如何避免 分析死锁产生的四个必要条件

    预防死锁最有效的方法是破坏死锁产生的四个必要条件中的一个或多个。死锁的四个必要条件分别是互斥、占有且等待、不可剥夺和循环等待;其中,互斥通常无法破坏,但可以减少使用;占有且等待可通过一次性申请所有资源来打破;不可剥夺可通过允许资源被剥夺打破;循环等待可通过按序申请资源解决。此外,reentrantl…

    2025年12月5日 java
    300
  • 误删回收站文件怎么恢复 试试这几种恢复方法

    在清理电脑回收站以腾出磁盘空间时,有时会不小心将重要文件一并清空。那么,一旦回收站被清空,这些文件是否就彻底无法找回了呢?其实不然,只要这些文件尚未被新数据覆盖,仍有机会完整恢复。本文将介绍几种实用且高效的恢复方式,助你尝试找回误删的文件。 一、借助“文件历史记录”功能进行恢复 Windows系统内…

    2025年12月5日 电脑教程
    000
  • js如何实现剪贴板历史 js剪贴板历史管理的4种技术方案

    要实现js剪贴板历史,核心在于拦截复制事件、存储复制内容并展示历史记录。1. 使用document.addeventlistener(‘copy’)监听复制事件,并通过e.clipboarddata.getdata获取内容;2. 用localstorage或indexeddb…

    2025年12月5日 web前端
    100
  • 如何利用JavaScript实现前端日志记录与用户行为分析?

    前端日志与用户行为分析可通过封装Logger模块实现,支持分级记录并上报;结合事件监听自动采集点击、路由变化等行为数据。 前端日志记录与用户行为分析能帮助开发者了解用户操作路径、发现潜在问题并优化产品体验。通过JavaScript,我们可以轻量高效地实现这些功能,无需依赖复杂工具也能获取关键数据。 …

    2025年12月5日
    000
  • 喜茶微信点单怎么用抖音券:详细教程及优惠攻略

    【引言】 作为新式茶饮的领军品牌,喜茶凭借其高品质原料与持续创新的产品赢得了广大消费者的喜爱。为提升服务效率与用户体验,喜茶全面上线了微信小程序点单功能,让用户无需排队即可完成下单。与此同时,喜茶携手抖音平台推出专属优惠活动——抖音券,进一步降低消费门槛。本文将为您全面解析如何在喜茶微信点单时使用抖…

    2025年12月5日
    000
  • win11怎么创建和挂载ISO镜像文件_Win11创建与挂载ISO虚拟光驱的方法

    Windows 11支持直接挂载ISO镜像作为虚拟光驱。1、右键ISO文件选择“挂载”即可在“此电脑”中显示为DVD驱动器;2、通过管理员权限的PowerShell使用Mount-DiskImage命令可实现命令行挂载;3、创建ISO文件可借助PowerShell或第三方工具如Oscdimg,将文件…

    2025年12月5日
    000
  • 抖音的私信定位在哪里?私信功能有什么作用?

    作为广受欢迎的社交平台,抖音中的私信功能是用户沟通的重要方式之一。然而不少刚接触抖音的朋友常常困惑:私信到底在哪?它又能用来做什么? 一、抖音私信入口在哪里? 其实,抖音的私信入口设计得十分直观,主要分布在手机App和电脑端两个场景中。 手机端抖音App 这是大多数用户使用的操作方式,主要有两个常用…

    2025年12月5日
    000
  • win10运行快捷键没反应如何办?win10运行快捷键没反应解决方法

    一、准备工作 要处理Win10系统中运行快捷键失效的问题,首先需要准备好相关条件。其中,一台可用的电脑是基础要求。 除此之外,还需要保持耐心,因为排查和解决问题往往需要一定时间。 同时,掌握一些网络搜索技巧也很重要,很多时候答案就隐藏在网络资源中等待我们去挖掘。 二、问题处理步骤 关于Win10运行…

    2025年12月5日
    000
  • 如何在Laravel中实现缓存机制

    laravel的缓存机制用于提升应用性能,通过存储耗时操作结果避免重复计算。1. 配置缓存驱动:在.env文件中设置cache_driver,如redis,并安装相应扩展;2. 使用cache facade进行缓存操作,包括put、get、has、forget等方法;3. 使用remember和pu…

    2025年12月5日
    000
  • 如何解决前端JS文件过大导致加载缓慢的问题,使用linkorb/jsmin-php助你轻松实现JS代码压缩优化

    可以通过一下地址学习composer:学习地址 在快节奏的互联网世界里,网站的加载速度是用户体验的生命线。用户往往没有耐心等待一个缓慢的页面,而搜索引擎也更青睐加载迅速的网站。作为一名开发者,我深知这一点,但最近在优化我的php项目时,却遇到了一个让人头疼的问题:前端的javascript文件随着功…

    开发工具 2025年12月5日
    000
  • Java中Executors类的用途 掌握线程池工厂的创建方法

    如何使用executors创建线程池?1.使用newfixedthreadpool(int nthreads)创建固定大小的线程池;2.使用newcachedthreadpool()创建可缓存线程池;3.使用newsinglethreadexecutor()创建单线程线程池;4.使用newsched…

    2025年12月5日 java
    000
  • js如何解析XML格式数据 处理XML数据的4种常用方法!

    在javascript中解析xml数据主要有四种方式:原生domparser、xmlhttprequest、第三方库(如jquery)以及fetch api配合domparser。使用domparser时,创建实例并调用parsefromstring方法解析xml字符串,返回document对象以便…

    2025年12月5日 web前端
    100
  • 解决WordPress博客首页无法显示页面标题的问题

    摘要:本文针对WordPress主题开发中,使用静态页面作为博客首页时,home.php无法正确显示页面标题的问题,提供了详细的解决方案。通过使用get_the_title()函数并结合get_option(‘page_for_posts’)获取文章页面的ID,从而正确显示博…

    2025年12月5日
    000
  • win8如何清理winsxs文件夹_win8安全清理Winsxs文件夹方法

    WinSxS文件夹占用过大可通过四种安全方法清理:一、使用磁盘清理工具,勾选“Windows更新清理”删除过期更新;二、通过DISM命令执行/analyzecomponentstore分析和/startcomponentcleanup清理;三、启用存储感知并配置自动删除临时文件;四、使用Dism++…

    2025年12月5日
    000
  • 如何在Laravel中处理表单提交

    在laravel中处理表单提交的步骤如下:1. 创建包含正确method、action属性和@csrf指令的html表单;2. 在routes/web.php或routes/api.php中定义路由,如route::post(‘/your-route’, ‘you…

    2025年12月5日
    100
  • 快兔网盘网页版怎么切换显示模式_快兔网盘网页版显示模式切换方法

    1、登录快兔网盘网页版进入主界面,在右上角点击显示模式图标可切换列表或缩略图模式;2、通过用户头像进入设置菜单,选择“文件显示”中的默认模式并保存,实现每次登录自动应用偏好视图。 如果您在使用快兔网盘网页版时,发现文件列表的显示效果不符合您的浏览习惯,可能是当前的显示模式不够直观。以下是切换显示模式…

    2025年12月5日
    000

发表回复

登录后才能评论
关注微信