2024年11月

来源:晓飞的算法工程笔记 公众号,转载请注明出处

论文: Collective Critics for Creative Story Generation

创新点


  • 提出了
    \({\tt CritiCS}\)
    的框架,旨在通过基于创造力标准的集体评议,创造性地增强故事计划和文本表现力。
  • 通过实验表明,
    \({\tt CritiCS}\)
    有效地创造了具有创造性和连贯性的故事,使用了多样化的标准、领导者和角色等关键组件。
  • \({\tt CritiCS}\)
    支持交互式写作,使人类用户能够介入评议并主动完善故事。

内容概述


使用大型语言模型(
LLMs
)生成几千字的叙事连贯的长篇故事一直是一项具有挑战性的任务。之前的研究通过提出不同的框架来解决这一挑战,这些框架创建了故事计划,并基于该计划生成长篇故事。然而,这些框架主要集中在维持故事的叙事连贯性上,往往忽视了故事计划中的创造力以及从这些计划中生成的故事的表现力,而这些都是吸引读者兴趣的理想特性。

论文提出了创意故事生成框架
Collective Critics for Creative Story

\({\tt CritiCS}\)
),该框架由计划优化阶段(
\({\tt CrPlan}\)
)和故事生成阶段(
\({\tt CrText}\)
)组成,旨在将协同修订机制融入长篇故事生成过程中。

在每个阶段,多位
LLM
评审者评估草稿,并根据评估创造力的标准(例如,叙事流的独特性和生成文本的生动性)提供改进建议。然后,一位领导者选择最有帮助于优化草稿的评审意见。这个修订过程经过多轮迭代,最终生成一个完整的计划和故事

广泛的人类评估表明,
\({\tt CritiCS}\)
显著提高了故事的创造力和读者的参与度,同时也保持了叙事的连贯性。此外,该框架的设计允许人类作者在整个评审过程中以任何角色积极参与,从而实现故事创作中的人机互动协作。

CritiCS


\({\tt CritiCS}\)
由两个阶段组成(
\({\tt CrPlan}\)

\({\tt CrText}\)
),利用大语言模型(
LLM
)的能力来创作创意故事,并将基于创意标准的评论过程纳入其中。

CrPlan


\({\tt CrPlan}\)
中,三个评论者根据三个标准评估故事计划的创造力:原创的主题和背景设置

不寻常的故事结构和不寻常的结局。这种评估确保为故事注入多样化的元素,同时赋予其新颖感。

上表展示了一个优化计划的例子,其中主角的孤独感被拟人化,从而增强了叙事背景的独特性。

首先,三个评论者各自提供建议,以利用他们的独特专业知识来增强草稿计划。接下来,领导者对三个建议进行评估、排名,并选择其认为最佳的一个。然后,将所选择的建议应用于完善计划。

为了进行详细的评论,三个评论者被赋予与故事计划相关的专业角色。同时,领导者被具身为文学编辑或创意写作专家,负责调和任何冲突。

整个过程重复进行若干轮,之后,计划评估者审查每轮候选计划,以选出最终一个在创造力与连贯性之间有效平衡的计划。

CrText


\({\tt CrText}\)
中,两位评论者根据来自
\({\tt CrPlan}\)
的计划审查已创作的故事,使用两个关注创意文本表现力的标准:图像和声音。

上表展示了一个经过优化的文本示例,其中动词
raised
被替换为
arched
,使得短语更具独特性。

图像表示读者被生动的心理意象所激发的程度。这包括视觉图像、声音、气味、身体感觉和情感(例如,从月球发出的柔和光辉、阴郁的阴影)。声音则指作者在创造独特且易于识别的写作风格方面的成功程度(例如,以恐怖故事风格书写、俚语、像
lol
这样的非正式语言)。与
\({\tt CrPlan}\)
类似,领导者选择两个建议中的一个来完善表达。


\({\tt CrPlan}\)
不同,在此过程中评论者没有角色,因为图像和声音标准提供了明确的表达修改指示,消除了需要角色来固定故事主题的必要。同时,由于每轮中的句子都在不同程度上被修改,因此没有评估者。

人机交互写作

\({\tt CritiCS}\)
能够促进人类写作者在修订过程中的积极参与,从而实现人类与机器在创意写作中的互动协作。人类参与者能够修改系统生成的评论或撰写自己的评论,也可以担任领导者的角色,负责评估和选择评论。

主要实验




如果本文对你有帮助,麻烦点个赞或在看呗~
更多内容请关注 微信公众号【晓飞的算法工程笔记】

work-life balance.

前言

本教程用于学习NetBox的基础使用,练习可使用官方Demo:
https://demo.netbox.dev/

NetBox 使用教程系列:
https://songxwn.com/tags/netbox-use/

重点:本篇为地区和站点

本教程范围

组织架构-站点

地区

地区是首先第一个要创建的东西,可以按等级写大洲、国家、省份、城市、市区等

如上图,从上到下,填写上级地区、名称、英文简写、描述等。

如上图所示,创建了多层级的区域。

站点

站点可以代表一个园区、数据中心、学校等,例如某个公司分支的机房。

  • 名称:可填写数据中心的名称或园区名称,如北京光环机房、上海齐网机房。

  • 缩写:可以写中文拼音简称等

  • 状态:代表这个运行状态,如规划中、已废弃、正在使用

  • 地区:关联相关的行政区域,如上面创建的朝阳区

  • 组:代表站点组,比如万国系列的机房、中信系列的机房等。都可以为一个站点组。具有相同点的就可以创建一个站点组关联。

  • AS编号:可以关联已创建的AS号,在很多划分中,不同站点使用不同的AS号进行建立BGP,方便管理。

  • 时区:代表站点所在地区的区域,如北京为东八区,一般选择 Asia/Shanghai

  • 描述:用于备注站点的简介信息

  • 租户和租户组:用于关联相关的租户。

  • 物理地址:填写站点的具体实体地址全称。

  • 快递地址:有些站点的快递地址与物理地址不太相同,需要另外填写。

  • 经纬度:经纬度是经度与纬度组成的坐标系统,是一种利用三度空间的球面来定义地球上的空间的球面坐标系统,能够标示地球上的任何一个位置。(方便用地图显示更精确的GPS位置)

PS:经纬度可以使用:
https://lbs.amap.com/tools/picker
获取

站点组

站点组,比如万国系列的机房、中信系列的机房等。都可以为一个站点组。具有相同点的就可以创建一个站点组关联。

  • 上级:可以支持多个层级的站点组,不过一般用不到。

  • 名称:如中信机房组、万国机房组

  • 缩写:英文或拼音缩写。

位置

位置代表站点里面的楼号、楼层、房间、机柜列等,用于标注机柜的具体内部位置。

PS:一般用机柜编号代表,非必要可以不填写。

  • 站点:用于关联已创建的站点

  • 上级:位置也可以有多层级,如楼号、楼层、房间为多层级。

  • 名称:可以填写全程

  • 缩写:英文或拼音缩写

  • 状态:运行、废弃等

  • 租户:可以关联具体的租户或租户组,比如这个房间整个租给了一个客户。

组织架构-租户

租户

租户表示用于管理目的的离散资源分组。通常,租户用于表示客户或组织内部的部门。

  • 名称:用于填写租户名称,如客户公司名字,或组织内部门名字

  • 缩写:英文或数字缩写

  • 组:用于关联租户组。

租户组

租户组可以递归嵌套以实现多级层次结构。例如,您可能有一个名为“客户集团”的组,其中包含按产品或客户团队分组的各个租户的子组。

组织架构-联系人

在整个NetBox中,联系人的信息并不太重要,算是信息的补充。

联系人

联系人代表出于管理原因和维护关系与 NetBox 中的对象相关联的个人或团体。例如,您可以为每个站点分配一个或多个技术或商务联系人。

  • 组:可关联联系人组

  • 职位:联系人的具体公司职位

  • 电话:联系电话

  • 电子邮箱:联系邮箱

  • 地址:实体地址

  • 链接:网址

联系人组

有相关联的联系人可以创建同一个联系人组进行管理,也支持层级创建。

联系人角色

如快递人、商务联系人、技术联系人、值班联系人等类型

联系人分配

查看已分配的联系人关系

技术交流群

发送邮件到 ➡️
me@songxwn.com

或者关注WX公众号:网工格物

微信扫码

博客(最先更新)

https://songxwn.com/

参考文档

https://github.com/netbox-community/netbox-zero-to-hero

在Python中,字典(
dict
)是一种非常强大的数据结构,它允许我们通过键(
key
)来存储和检索值(
value
)。有时候,我们可能想要根据多个键来检索或操作字典中的数据。虽然Python的字典不直接支持使用多个键进行索引,但我们可以通过一些技巧来实现这一功能。

下面,我将展示几种处理包含多个键的字典的方法,并提供详细的代码示例。

1.方法一:使用元组作为键

我们可以将多个键组合成一个元组,并使用这个元组作为字典的键。

(1)代码示例

# 创建一个字典,使用元组作为键
multi_key_dict = {
    (1, 'a'): 'value1',
    (2, 'b'): 'value2',
    (3, 'c'): 'value3'
}
 
# 检索值
key = (2, 'b')
value = multi_key_dict.get(key)
print(f"The value for key {key} is {value}")
 
# 插入新值
multi_key_dict[(4, 'd')] = 'value4'
print(multi_key_dict)
 
# 更新值
multi_key_dict[(1, 'a')] = 'new_value1'
print(multi_key_dict)

(2)输出

The value for key (2, 'b') is value2
{(1, 'a'): 'new_value1', (2, 'b'): 'value2', (3, 'c'): 'value3', (4, 'd'): 'value4'}
{(1, 'a'): 'new_value1', (2, 'b'): 'value2', (3, 'c'): 'value3', (4, 'd'): 'value4'}

2.方法二:使用嵌套字典

对于更复杂的场景,我们可以使用嵌套字典来组织数据。

(1)代码示例

# 创建一个嵌套字典
nested_dict = {
    1: {'a': 'value1_a', 'b': 'value1_b'},
    2: {'a': 'value2_a', 'c': 'value2_c'},
    3: {'b': 'value3_b', 'c': 'value3_c'}
}
 
# 检索值
primary_key = 2
secondary_key = 'a'
value = nested_dict.get(primary_key, {}).get(secondary_key)
print(f"The value for keys {primary_key} and {secondary_key} is {value}")
 
# 插入新值
primary_key_new = 4
secondary_key_new = 'd'
value_new = 'value4_d'
if primary_key_new not in nested_dict:
    nested_dict[primary_key_new] = {}
nested_dict[primary_key_new][secondary_key_new] = value_new
print(nested_dict)
 
# 更新值
nested_dict[1]['a'] = 'new_value1_a'
print(nested_dict)

(2)输出

The value for keys 2 and a is value2_a
{1: {'a': 'new_value1_a', 'b': 'value1_b'}, 2: {'a': 'value2_a', 'c': 'value2_c'}, 3: {'b': 'value3_b', 'c': 'value3_c'}, 4: {'d': 'value4_d'}}
{1: {'a': 'new_value1_a', 'b': 'value1_b'}, 2: {'a': 'value2_a', 'c': 'value2_c'}, 3: {'b': 'value3_b', 'c': 'value3_c'}, 4: {'d': 'value4_d'}}

3.方法三:使用
collections.defaultdict

对于需要频繁插入新键的场景,
collections.defaultdict
可以简化代码。

(1)代码示例

from collections import defaultdict
 
# 创建一个嵌套defaultdict
nested_defaultdict = defaultdict(lambda: defaultdict(str))
 
# 插入值
nested_defaultdict[1]['a'] = 'value1_a'
nested_defaultdict[2]['b'] = 'value2_b'
nested_defaultdict[3]['c']['d'] = 'value3_c_d'  # 注意这里我们创建了一个更深层次的嵌套
 
# 检索值
primary_key = 2
secondary_key = 'b'
value = nested_defaultdict[primary_key][secondary_key]
print(f"The value for keys {primary_key} and {secondary_key} is {value}")
 
# 更新值
nested_defaultdict[1]['a'] = 'new_value1_a'
print(nested_defaultdict)

(2)输出

The value for keys 2 and b is value2_b
defaultdict(<function <lambda> at 0x...>, {1: defaultdict(str, {'a': 'new_value1_a'}), 2: defaultdict(str, {'b': 'value2_b'}), 3: defaultdict(str, {'c': defaultdict(str, {'d': 'value3_c_d'})})})

4.实际应用和参考价值

(1)
数据存储
:在需要存储多维数据或具有多个属性的对象时,这些方法非常有用。

(2)
配置管理
:可以将配置选项组织成嵌套字典,以便更方便地访问和修改。

(3)
缓存
:在缓存系统中,可以使用多个键来唯一标识缓存项,从而避免冲突。

5.注意事项

(1)
键的唯一性
:在方法一中,元组作为键必须是唯一的,否则后面的值会覆盖前面的值。

(2)
性能
:嵌套字典和
defaultdict
在检索和插入操作时的性能通常是可以接受的,但在处理大量数据时,可能需要考虑优化。

(3)
可读性
:使用嵌套结构时,代码的可读性可能会降低,因此建议添加适当的注释来提高代码的可维护性。

6. Python dict支持哪些数据类型作为键

在Python中,
dict
(字典)是一种非常灵活且强大的数据结构,它允许我们使用键值对(key-value pairs)来存储和检索数据。关于
dict
支持的键的数据类型,有以下几点需要注意:

(1)支持的数据类型

不可变类型

  • 整数

    int
    ):包括正整数、负整数和零。例如,
    {1: 'one', -2: 'two', 0: 'zero'}
  • 浮点数

    float
    ):虽然可以使用浮点数作为键,但由于浮点数的精度问题,一般不推荐使用。例如,
    {1.0: 'one', 2.5: 'two point five'}
    (但需注意精度问题可能导致的键冲突)。
  • 字符串

    str
    ):这是最常用的键类型之一,字符串可以是任意长度的字符序列。例如,
    {'apple': 'fruit', 'car': 'vehicle'}
  • 元组

    tuple
    ):元组是由多个元素组成的有序集合,由于它是不可变的,因此可以用作字典的键。例如,
    {(1, 2): 'pair', (3, 4, 5): 'triplet'}
  • 布尔值

    bool
    ):
    True

    False
    也可以作为键。例如,
    {True: 'yes', False: 'no'}
  • NoneType

    None
    也可以作为键。例如,
    {None: 'no value'}
  • frozenset
    :这是一个不可变的集合,因此可以用作键。例如,
    {frozenset([1, 2]): 'frozen set of 1 and 2'}

不可变类型的自定义对象

  • 如果自定义的类对象实现了
    __hash__()
    方法和
    __eq__()
    方法,并且它们是不可变的(即对象的状态在创建后不会改变),那么这样的对象也可以用作字典的键。

(2)不支持的数据类型

可变类型
:由于字典要求键必须是可哈希的(hashable),而可变类型(如列表、集合、字典本身等)由于其内容可以改变,因此是不可哈希的,不能用作字典的键。

(3)示例代码

以下是一个包含多种类型键的字典示例:

my_dict = {
    1: 'integer key',
    -3.14: 'float key',  # 注意:一般不推荐使用浮点数作为键
    'string': 'string key',
    (1, 2, 3): 'tuple key',
    True: 'boolean key',
    None: 'none key',
    frozenset([4, 5]): 'frozenset key'
}
 
# 访问字典中的值
print(my_dict[1])         # 输出: integer key
print(my_dict[(1, 2, 3)]) # 输出: tuple key
print(my_dict[True])      # 输出: boolean key
 
# 尝试使用不支持的数据类型作为键(会导致错误)
# my_dict = {[1, 2]: 'list key'}  # TypeError: unhashable type: 'list'

(4)结论

Python的
dict
支持多种不可变类型作为键,包括整数、浮点数(尽管有精度问题)、字符串、元组、布尔值、
NoneType

frozenset
等。然而,它不支持可变类型(如列表、集合、字典等)作为键。了解这些规则有助于我们更有效地使用Python的字典数据结构。

前言

由于Netbox 官方的中文语言日渐完善,所以新出一个使用官方Docker源部署和升级的教程。

Netbox 系列文章:
https://songxwn.com/categories/NetBox/

环境介绍

Rocky Linux 9.5 (理论上也适用于RHEL系列的7-9版本)

南京大学镜像源ISO镜像下载:
https://mirror.nju.edu.cn/rocky/9/isos/x86_64/Rocky-9-latest-x86_64-minimal.iso

环境配置

systemctl disable --now firewalld
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config && setenforce 0

# 关闭防火墙和SELinux。


dnf install tree vim bash-completion tar git -y
# 安装一些工具,用于之后的部署

Docker-CE 环境安装

yum install -y yum-utils

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

sed -i 's+https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo



yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

参考清华大学源:
https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/

Docker国内镜像加速器配置

sudo mkdir -p /etc/docker

# 创建文件夹


sudo tee /etc/docker/daemon.json <<-'EOF'
{
     "registry-mirrors": [
    "https://proxy.1panel.live",
    "https://dockerpull.org",
    "https://hub1.nat.tf",
    "docker.m.daocloud.io"

     ]
}
EOF

# 指定镜像源


sudo systemctl daemon-reload
sudo systemctl restart docker

# 重载重启后生效

docker info | grep https

# 验证

docker pull hello-world

# 拉取镜像验证

PS: 或者参考
https://songxwn.com/cf-works-DockerHub-Proxy/
自行搭建

Netbox部署



cd /opt

git clone -b release https://github.com/netbox-community/netbox-docker.git

# git获取官方库,国内可使用git clone -b release https://gitee.com/songxwn/netbox-docker.git


cd /opt/netbox-docker

tee docker-compose.override.yml <<EOF
services:
  netbox:
    ports:
      - 8000:8080
EOF

# 创建端口映射规则文件,使用8000端口对外访问


docker compose pull

# 拉取镜像


docker compose up -d

# 启动镜像,第一次会比较久


docker compose logs netbox 

# 查看日志,确认状态

创建用户(需要输入账号、邮箱和两次密码)

docker compose exec netbox /opt/netbox/netbox/manage.py createsuperuser

## 等容器启动完成后,创建后可访问 8000端口进行登录。

配置Nginx 作为反向代理


dnf install nginx -y
# 安装Nginx

vim /etc/nginx/conf.d/netbox.conf
# 创建配置文件,注意修改netbox.songxwn.com 为自己的域名。反向代理到8000端口,端口也需要自己修改。

server {
    listen 80;
    # CHANGE THIS TO YOUR SERVER'S NAME
    server_name netbox.songxwn.com;
    client_max_body_size 25m;
    fastcgi_connect_timeout 1200s;
    fastcgi_send_timeout 1200s;
    fastcgi_read_timeout 1200s;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 256k;
    location /static/ {
        alias /opt/netbox/netbox/static/;
    }
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
		proxy_connect_timeout       600;
        proxy_send_timeout          600;
        proxy_read_timeout          600;
        send_timeout                600;
    }
}
systemctl enable --now nginx
# 配置启动并开机启动
systemctl status nginx
# 查看状态


Netbox 升级


cd /opt/netbox-docker

docker compose pull

# 拉最新镜像

docker compose down

docker compose up -d

# 以最新镜像重新启动

技术交流群

发送邮件到 ➡️
me@songxwn.com

或者关注WX公众号:网工格物

微信扫码

博客(最先更新)

https://songxwn.com/

问题描述

在抓取到网络包之后,如何来获取TLS信息呢?比如使用的是是么加密套件呢?

因为在应用层面,获取的错误信息非常简单:

An TLS 1.2 connection request was received from a remote client application, but non of the cipher suites supported by the client application are supported by the server. The connection request has failed.

从远程客户端应用程序收到 TLS 1.2 连接请求,但服务器不支持客户端应用程序支持的任何密码套件。连接请求失败。

所以,我们如何从客户端抓取的网络包中分析出 TLS 所所以用的 Cipher Suites信息呢?

问题解答

通过咨询M365 Copilot,得到了想要的答案:

在Wireshark中分析SSL相关信息(例如使用的加密套件)可以通过以下步骤进行:

1.
启动Wireshark并抓包:
首先,启动Wireshark并开始抓取网络流量。确保你正在捕获包含SSL/TLS流量的网络接口。
2.
过滤SSL/TLS流量:
在Wireshark的过滤器栏中输入ssl或tls,以便只显示SSL/TLS流量。这将帮助你更容易找到相关的数据包。
3.
找到SSL握手包:
在过滤后的流量中,找到SSL握手包。通常,这些包包括Client Hello和Server Hello消息。你可以通过查看协议列中的Client Hello和Server Hello来识别这些包。
4.
查看加密套件:

  • Client Hello:双击Client Hello包,在详细信息窗格中展开Secure Sockets Layer或Transport Layer Security部分。你会看到一个名为Cipher Suites的字段,其中列出了客户端支持的加密套件。
  • Server Hello:双击Server Hello包,在详细信息窗格中展开Secure Sockets Layer或Transport Layer Security部分。你会看到一个名为Cipher Suite的字段,其中列出了服务器选择的加密套件。

5.
解密SSL/TLS流量(可选)
:如果你有服务器的私钥,可以在Wireshark中配置解密SSL/TLS流量。步骤如下:

  • 选择Edit > Preferences。
  • 在Preferences窗口中展开Protocols,然后选择SSL。
  • 在RSA keys list字段中,输入服务器的IP地址、端口、协议和私钥文件路径。

通过这些步骤,你可以在Wireshark中分析SSL相关信息并查看使用的加密套件。

实际演示

根据以上的解答,实际实验去查看两个数据包:一个是正常建立TLS连接,一个是无法建立TLS连接。

第一步:根据目的IP地址过滤网络包

打开 .pcapng 后缀名的网络包,根据目的IP地址进行过滤 ( 如:ip.addr ==
5.13.9.7

第二步:查看TCP请求中的Client Hello 信息

Transport Layer Security --> TLSv1.2 Record Layer --> Handshake Protocol:Client Hello --> Cipher Suites

Cipher Suites (12 suites)

Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
Cipher Suite: TLS_RSA_WITH_RC4_128_SHA (0x0005)
Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA (0x0032)
Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA (0x0038)
Cipher Suite: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA (0x0013)
Cipher Suite: TLS_RSA_WITH_RC4_128_MD5 (0x0004)

第三步:查看TCP请求中的Server Hello 信息

Transport Layer Security --> TLSv1.2 Record Layer --> Handshake Protocol:Server Hello --> Cipher Suites

[正常建立连接]

Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)

[不能正常建立连接]

在客户端发送Client Hell后,服务端返回的Server Hello包中,

Transport Layer Security

TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Protocol Version)
Content Type: Alert (21)
Version: TLS 1.2 (0x0303)
Length: 2
Alert Message
Level: Fatal (2)
Description: Protocol Version (70)

演示动画:

参考资料

Wireshark:
https://www.wireshark.org/