【Java-LangChain:面向开发者的提示工程-8】聊天机器人
第八章 聊天机器人
使用一个大型语言模型的一个令人兴奋的事情是,我们可以用它来构建一个定制的聊天机器人 (Chatbot) ,只需要很少的工作量。在这一节中,我们将探索如何利用聊天的方式,与个性化(或专门针对特定任务或行为的)聊天机器人进行扩展对话。
像 ChatGPT 这样的聊天模型实际上是组装成以一系列消息作为输入,并返回一个模型生成的消息作为输出的。这种聊天格式原本的设计目标是简便多轮对话,但我们通过之前的学习可以知道,它对于不会涉及任何对话的单轮任务也同样有用。
环境配置
参考第二章的 环境配置小节内容即可。
身份与上下文构建
接下来,我们将定义两个辅助函数。
第一个方法已经陪伴了您一整个教程,即 getCompletion
,其适用于单轮对话。我们将 Prompt 放入某种类似用户消息的对话框中。
另一个称为 getCompletionFromMessage
,传入一个消息列表。这些消息可以来自大量不同的角色 (roles) ,我们会描述一下这些角色。
第一条消息中,我们以系统身份发送系统消息 (system message) ,它提供了一个总体的指示。系统消息则有助于设置助手的行为和角色,并作为对话的高级指示。你可以想象它在助手的耳边低语,引导它的回应,而用户不会注意到系统消息。因此,作为用户,如果你曾经使用过 ChatGPT,您可能从来不知道 ChatGPT 的系统消息是什么,这是有意为之的。系统消息的好处是为开发者提供了一种方法,在不让请求本身成为对话的一部分的情况下,引导助手并指导其回应。
在 ChatGPT 网页界面中,您的消息称为用户消息,而 ChatGPT 的消息称为助手消息。但在构建聊天机器人时,在发送了系统消息之后,您的角色可以仅作为用户 (user) ;也可以在用户和助手 (assistant) 之间交替,从而提供对话上下文。
现在让我们尝试在对话中使用这些消息。我们将使用上面的函数来获取从这些消息中得到的回答,同时,使用更高的温度 (temperature)(越高生成的越多样,更多内容见第七章)。
系统消息说,你是一个说话像莎士比亚的助手。这是我们向助手描述它应该如何表现的方式。然后,第一个用户消息是给我讲个笑话。接下来以助手身份给出回复是,为什么鸡会过马路? 最后发送用户消息是我不知道。
List<ChatMessage> chatMessages = new ArrayList<>();ChatMessage message = new ChatMessage();message.setRole("system");message.setContent("你是一个像莎士比亚一样说话的助手。");chatMessages.add(message);ChatMessage message1 = new ChatMessage();message1.setRole("user");message1.setContent("给我讲个笑话");chatMessages.add(message1);ChatMessage message2 = new ChatMessage();message2.setRole("assistant");message2.setContent("鸡为什么过马路");chatMessages.add(message2);ChatMessage message3 = new ChatMessage();message3.setRole("user");message3.setContent("我不知道");chatMessages.add(message3);String result = this.getCompletionFromMessage(chatMessages, 1.5d);log.info("iterative1:\n{}", result);
因为它想躲过汤锅! 这个笑话有些“愚蠢”,与幽默玩了一个常见的危险情境,引起一些意外,以尽力让人们笑一笑。这种类型的笑话强调了荒诞和意想不到的情节。
让我们看另一个例子。助手的消息是你是一个友好的聊天机器人,第一个用户消息是嗨,我叫Isa。我们想要得到第一个用户消息。
List<ChatMessage> chatMessages = new ArrayList<>();ChatMessage message = new ChatMessage();message.setRole("system");message.setContent("你是个友好的聊天机器人。");chatMessages.add(message);ChatMessage message1 = new ChatMessage();message1.setRole("user");message1.setContent("Hi, 我是Isa。");chatMessages.add(message1);String result = this.getCompletionFromMessage(chatMessages, 1.5d);log.info("iterative2:\n{}", result);
嗨Isa,很高兴认识你!有什么我可以帮助你的吗?
让我们再试一个例子。系统消息是,你是一个友好的聊天机器人,第一个用户消息是,是的,你能提醒我我的名字是什么吗?
List<ChatMessage> chatMessages = new ArrayList<>();ChatMessage message = new ChatMessage();message.setRole("system");message.setContent("你是个友好的聊天机器人。");chatMessages.add(message);ChatMessage message1 = new ChatMessage();message1.setRole("user");message1.setContent("好,你能提醒我,我的名字是什么吗?");chatMessages.add(message1);String result = this.getCompletionFromMessage(chatMessages, 1.5d);log.info("iterative3:\n{}", result);
当然可以!请告诉我你的名字,我将会一直记得。
如上所见,模型实际上并不知道我的名字。
因此,每次与语言模型的交互都互相独立,这意味着我们必须提供所有相关的消息,以便模型在当前对话中进行引用。如果想让模型引用或 “记住” 对话的早期部分,则必须在模型的输入中提供早期的交流。我们将其称为上下文 (context) 。尝试以下示例。
List<ChatMessage> chatMessages = new ArrayList<>();ChatMessage message = new ChatMessage();message.setRole("system");message.setContent("你是个友好的聊天机器人。");chatMessages.add(message);ChatMessage message1 = new ChatMessage();message1.setRole("user");message1.setContent("Hi, 我是Isa");chatMessages.add(message1);ChatMessage message2 = new ChatMessage();message2.setRole("assistant");message2.setContent("Hi Isa! 很高兴认识你。今天有什么可以帮到你的吗?");chatMessages.add(message2);ChatMessage message3 = new ChatMessage();message3.setRole("user");message3.setContent("是的,你可以提醒我, 我的名字是什么?");chatMessages.add(message3);String result = this.getCompletionFromMessage(chatMessages, 1.5d);log.info("iterative4:\n{}", result);
当然,Isa,你的名字是Isa。请问有什么具体的提醒需要我帮助你吗?
现在我们已经给模型提供了上下文,也就是之前的对话中提到的我的名字,然后我们会问同样的问题,也就是我的名字是什么。因为模型有了需要的全部上下文,所以它能够做出回应,就像我们在输入的消息列表中看到的一样。
订餐机器人
现在,我们构建一个 “订餐机器人”,我们需要它自动收集用户信息,接受比萨饼店的订单。
下面这个函数将收集我们的用户消息,以便我们可以避免像刚才一样手动输入。这个函数将从我们下面构建的用户界面中收集 Prompt ,然后将其附加到一个名为上下文( context )的列表中,并在每次调用模型时使用该上下文。
模型的响应也会添加到上下文中,所以用户消息和模型消息都被添加到上下文中,上下文逐渐变长。这样,模型就有了需要的信息来确定下一步要做什么。
现在,我们将设置并运行这个 UI 来显示订单机器人。初始的上下文包含了包含菜单的系统消息,在每次调用时都会使用。此后随着对话进行,上下文也会不断增长。
Java快速转换到大模型开发:
配套课程的所有代码已经发布在:https://github.com/Starcloud-Cloud/java-langchain
课程合作请留言
相关文章:
【Java-LangChain:面向开发者的提示工程-8】聊天机器人
第八章 聊天机器人 使用一个大型语言模型的一个令人兴奋的事情是,我们可以用它来构建一个定制的聊天机器人 (Chatbot) ,只需要很少的工作量。在这一节中,我们将探索如何利用聊天的方式,与个性化(或专门针对特定任务或…...
利用t.ppft.interval分别计算T分布置信区间[实例]
scipy.stats.t.interval用于计算t分布的置信区间,即给定置信水平时,计算对应的置信区间的下限和上限。 scipy.stats.t.ppf用于计算t分布的百分位点,即给定百分位数(概率)时,该函数返回给定百分位数对应的t…...

软件工程第三周
可行性研究 续 表达工作量的方式 LOC估算:Line of Code 估算公式S(Sopt4SmSpess)/6 FP:功能点 1. LOC (Line of Code) 估算 定义:LOC是指一个软件项目中的代码行数。 2. FP (Function Points) 估算 定义:FP是基于软件的功能性和…...

动态链接那些事
1、为什么要动态链接 1.1 空间浪费 对于静态链接来说,在程序运行之前,会将程序所需的所有模块编译、链接成一个可执行文件。这种情况下,如果 Program1 和 Program2 都需要用到 Lib.o 模块,那么,内存中和磁盘中实际上就…...

力扣:118. 杨辉三角(Python3)
题目: 给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 来源:力扣(LeetCode) 链接:力扣(LeetCode)官…...

QGIS文章二——DEM高程裁剪和3D地形图
经常看到别人基于高程文件制作出精美的3D地图,笔者按照互联网几种制作方式进行尝试后,写的DEM高程裁剪和3D地形图教程,或许其中有一些错误的,也请指出。 本文基于海南省的shp文件和海南省DEM高程文件,制作海口地区的3D…...

【kubernetes】kubernetes中的StatefulSet使用
TOC 1 为什么需要StatefulSet 常规的应用通常使用Deployment,如果需要在所有机器上部署则使用DaemonSet,但是有这样一类应用,它们在运行时需要存储一些数据,并且当Pod在其它节点上重建时也希望这些数据能够在重建后的Pod上获取&…...
创建文件夹
/storage/emulated/0/代码文件/ 没有就创建 文件名命名方法:编号. 库 时间戳 使用Python的os模块来检查目录是否存在,并在不存在时创建它。下面是一个示例代码,演示了如何检查指定路径下的目录是否存在,若不存在则创建…...
点击router-link时候会发生什么?
当你点击链接或按钮时,将会导航到 User 组件,就会显示相应的用户 ID。 这里说一下执行流程,当点击一个 router-link 时,Vue Router会执行以下流程: 1)点击事件触发: 当你点击 router-link 组件时…...
【Spring】@Bean方法中存在继承如何分析
文章目录 1. 提问:如果让您分析Spring MVC的原理,您如何开始分析呢2. 如何破局3. 资料参考 本文主要介绍:如何分析 Bean方法存在继承 或 Bean方法中存在调用子类方法。 1. 提问:如果让您分析Spring MVC的原理,您如何…...

【Vim 插件管理器】Vim-plug和Vim-vbundle的区别
- vundle是一款老款的插件管理工具 - vim-plug相对较新,特点是支持异步加载,相比vundle而言 Vim-plug 是一个自由、开源、速度非常快的、极简的 vim 插件管理器。它可以并行地安装或更新插件。你还可以回滚更新。它创建浅层克隆shallow clone最小化磁盘…...

电子计算机核心发展(继电器-真空管-晶体管)
目录 继电器 最大的机电计算机之一——哈弗Mark1号,IBM1944年 背景 组成 性能 核心——继电器 简介 缺点 速度 齿轮磨损 Bug的由来 真空管诞生 组成 控制开关电流 继电器对比 磨损 速度 缺点 影响 代表 第一个可编程计算机 第一个真正通用&am…...

SDI-12协议与STM32 进行uart通信
场景是用stm32与一款温湿度传感器通信,不过是基于SDI-12协议,SDI-12时序和UART类似,故采用UART传输,原理图如下 其中DIR_OUT_SDI是一个IO引脚,控制UART_TX_SDI是否使能,U10是三态门IC,即拉低DIR…...
JS中的强制类型转换
JavaScript 中有多种强制类型转换的方式,可以将一个数据类型转换为另一种数据类型。这可以通过一些内置函数或操作符来实现。 显式类型转换(强制类型转换): 显式类型转换是通过特定的函数或操作符来明确指定要进行的类型转换。以下…...

WebSocket实战之四WSS配置
一、前言 上一篇文章WebSocket实战之三遇上PAC ,碰到的问题只能上安全的WebSocket(WSS)才能解决,配置证书还是挺麻烦的,主要是每年都需要重新更新证书,我配置过的证书最长有效期也只有两年,搞不…...

veImageX 演进之路:Web 图片加载提速50%
背景说明 火山引擎veImageX演进之路主要介绍了veImageX在字节内部从2012年随着字节成长过程中逐步演进的过程,演进中包括V1、V2、V3版本并最终面向行业输出;整个演进过程中包括服务端、客户端、网络库、业务场景与优化等多个角度介绍在图像处理压缩、省成…...

WebSocket实战之五JSR356
一、前言 前几篇WebSocket例子服务端我是用NodeJS实现,这一篇我们用Java来搭建一个WebSocket服务端,从2011年WebSocket协议RFC6455发布后,大多数浏览器都实现了WebSocket协议客户端的API,而对于服务端Java也定义了一个规范JSR356,即Java API for WebSoc…...
flask-sqlalchemy结合Blueprint遇到循环引入问题的解决方案
想要用flask_sqlalchemy结合Blueprint分模块写一下SQL的增删改查接口,结果发现有循环引入问题。 一开始,我在app.py中使用db SQLAlchemy(app)创建数据库对象;并且使用app.register_blueprint(db_bp, url_prefix/db)注册蓝图。 这使得我的依…...

05_对象性能模式
对象性能模式 面向对象很好地解决了“抽象”的问题,但是必不可免地要付出定的代价。对于通常情况来讲,面向对象的成本大都可以忽略计。但是某些情况,面向对象所带来的成本必须谨慎处理。 典型模型: SingletonFlyweight Singleton 单件模式…...

快速选择排序
"你经过我每个灿烂时刻,我才真正学会如你般自由" 前些天有些无聊,想试试自己写的快排能否过leetcode上的排序算法题。结果是,不用截图可想而知,肯定是没过的,否则也不会有这篇文章的产出。 这份快排算法代码…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...