0%

JavaScript 标准提供了 EventSource 接口,用于与服务器发送事件(Server-Sent Events,SSE)接口进行通信。

1
2
3
4
5
6
7
8
9
var evtSource = new EventSource("sse.php");
var eventList = document.querySelector("ul");

evtSource.onmessage = function (e) {
var newElement = document.createElement("li");

newElement.textContent = "message: " + e.data;
eventList.appendChild(newElement);
};

上面的代码片段来源于 MDN,展示了 EventSource 的基本用法:通过后端接口 "sse.php" 接收事件,并在 onmessage 回调中处理事件(本例中是将事件数据添加到页面的列表中)。

然而,EventSource 存在一些局限性,最明显的是它仅支持连接到 GET 接口,无法使用 POST 等其他 HTTP 方法,也无法通过 HTTP Body 传输数据。这对于一些需要通过 POST 请求发送参数的应用场景会受到限制。

在生成式 AI 应用中,OpenAI 的对话接口支持流式传输数据,这种传输方式通常实现为 SSE。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import OpenAI from "openai";

const openai = new OpenAI();

async function main() {
const stream = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Say this is a test" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || "");
}
}

main();
Read more »

Deno 2.0发布

Deno 2.0已经正式发布,其最大的亮点是大幅增强了与 Node.js 的兼容性(支持 package.json 和 node_modules 目录)。这使得从 Node.js 迁移到 Deno 变得更加简便,特别是在处理旧有项目时,极大地降低了迁移成本。

最近我也在项目中开始使用 Deno,尤其是作为 Supabase Edge Functions 的运行时环境。相比 Node.js,Deno 更加轻量,适合无服务器(serverless)架构中的后端 JavaScript 运行时。

Non GIL Python的性能提升

Youtube 视频How Much FASTER Is Python 3.13 Without the GIL?讨论了无GIL的Python 3.13在多线程场景下带来的性能提升以及在无GIL的Python版本中编写代码的注意事项。

2024年诺贝尔物理学奖

2024年诺贝尔物理学奖授予了约翰·霍普菲尔德和杰弗里·辛顿,以表彰他们在人工神经网络实现机器学习方面的基础性发现和发明。

只能说,Physics的cs是Compute Science。

2024年诺贝尔化学奖

2024年诺贝尔化学奖授予了美国华盛顿大学的戴维·贝克(David Baker)、英国伦敦谷歌DeepMind公司的德米斯·哈萨比斯(Demis Hassabis)和约翰·江珀(John M. Jumper),以表彰他们在蛋白质设计和蛋白质结构预测领域的贡献。

Chemistry的cs也是Computer Science。

工作吐槽

  • GPU云服务器的价格着实有点高。

Python 3.13 正式发布

Python 3.13 于 10 月 7 日正式发布,带来的新特性有:

  • REPL 体验优化:增加了多彩输出、支持多行编辑,并且 exit 和 help 命令可以直接使用,无需加括号。
  • 异常提示增强:更智能地提示错误,例如在导入与第三方模块同名的本地模块时提供清晰的警告。
  • 非 GIL 版本:解锁了多线程能力,但需要独立编译 Python,同时使用的 C 扩展库也需额外适配和编译。
  • JIT 支持:引入了即时编译技术(JIT),提升性能,但需单独编译。

Tauri 2.0 稳定版发布

Tauri 2.0 稳定版于 10 月 2 日正式发布,新特性有:

  • 移动支持:扩展了单一体验,现在包括 iOS 和 Android 平台的支持。
  • 插件系统:构建了一个更先进的插件系统,允许社区更容易地贡献和维护插件。
  • 系统权限管理:引入了基于权限、范围和能力的灵活但简单的访问控制系统。
  • 性能优化:改进了 IPC 层,支持 Raw Payloads,提高了数据传输效率。
  • 多平台开发体验:改进了开发工具和流程,使得桌面和移动平台的开发体验更加一致。

其他消息

  • 鸿蒙 Next 开启公测,腾讯提供了一个适配鸿蒙 Next 的微信版本(目前看来不支持小程序)。

工作吐槽

  • 苹果开发者账号注册有些麻烦,要求使用 Apple ID 在 Mac OS 或者 iOS 上的苹果开发者 App 中注册,还需要每年一百美元的费用。

在编程中,循环是一个常见的结构,用于重复执行某个动作直到满足特定条件。本文以一个简单的猜数字游戏为例,介绍了三种不同的循环方式以及如何使用 iter 函数来优化代码。

1. 使用 while True 循环

最基本的方式是使用 while True 循环,这种方法通过在循环内部使用 break 语句终止循环。例如:

1
2
3
4
5
6
7
8
9
10
while True:
guess = int(input("Enter an integer(1-100) : "))

if guess == NUMBER:
print("Congratulations, you guessed it.")
break
elif guess < NUMBER:
print("No, it is a little higher than that.")
else:
print("No, it is a little lower than that.")

虽然这种方法很常见,但它有一个“坏味道”,因为 while True 暗示了一个无限循环,可能会导致代码难以理解和维护。

2. 使用赋值表达式优化 while 循环

Python 3.8 引入了赋值表达式(即“海象运算符”:=),可以将输入和条件检查合并,避免使用 while True:

1
2
3
4
5
6
while (guess := int(input("Enter an integer(1-100) : "))) != NUMBER:
if guess < NUMBER:
print("No, it is a little higher than that.")
else:
print("No, it is a little lower than that.")
print("Congratulations, you guessed it.")

这种方式减少了代码的冗余,使得循环条件更加明确。

3. 使用 iter 函数和 for 循环

iter 函数可以将一个可调用对象转换为生成器,并通过传入一个哨兵值来控制生成器的终止。使用 iter 函数,我们可以用 for 循环来替代 while 循环:

1
2
3
4
5
6
7
for guess in iter(lambda: int(input()), NUMBER):
if guess < NUMBER:
print("No, it is a little higher than that.")
else:
print("No, it is a little lower than that.")

print("Congratulations, you guessed it.")

与 while True 循环相比,for 循环在代码审查中更具有说服力,因为它更清晰地表达了循环的结束条件。

使用 iter 函数实现附加功能

iter 函数的另一个优势是它可以很容易地结合 enumerate 函数来实现附加功能,例如统计猜测次数:

1
2
3
4
5
6
7
8
for times, guess in enumerate(iter(lambda: int(input()), NUMBER), start=1):
if guess < NUMBER:
print(f"No, it is a little higher than that. Wrong Guess Times: {times}")
else:
print(f"No, it is a little lower than that. Wrong Guess Times: {times}")


print(f"Congratulations, you guessed it. Wrong Guess Times: {times}")

相比之下,使用 while 循环则需要手动维护一个计数变量,这增加了代码的复杂性。

1
2
3
4
5
6
7
8
9
times = 0
while (guess := int(input("Enter an integer(1-100) : "))) != NUMBER:
times += 1
if guess < NUMBER:
print(f"No, it is a little higher than that. Wrong Guess Times: {times}")
else:
print(f"No, it is a little lower than that. Wrong Guess Times: {times}")

print(f"Congratulations, you guessed it. Wrong Guess Times: {times}")

总结

本文通过实例介绍了如何在 Python 中使用不同的循环结构,特别是如何利用 iter 函数优化代码。通过减少对 while True 循环的依赖,代码将更易读、更易维护。希望读者在未来的编程中能够灵活应用这些技巧。

大语言模型的函数调用能力是指其能够调用外部工具或API来实现特定功能的能力。这种能力使得大语言模型能够超越自身的限制,访问实时信息、执行复杂计算或操作外部系统,从而增强其解决问题的能力。

Openai的对话模型通过其API支持函数调用功能,其实现方式为:

  • API参数设置:在调用OpenAI的API时,可以通过tools参数提供函数调用的规范。这包括函数的名称、描述和参数。
  • 模型输出处理:模型不会直接执行函数调用,而是生成一个包含函数名称和参数的JSON对象。开发人员需要使用这个对象来实际调用函数。
  • 函数调用的响应:如果模型决定调用函数,其输出将包含在finish_reason为tool_call的响应中,包含要调用的函数和参数信息。
  • 手动调用函数后,创建一个role为tool的消息添加到历史消息列表中,再调用一次对话模型。模型会根据函数调用的结果返回相应的信息。

llm-function-call

Read more »

我从去年末开始参与 Windows C++客户端的开发工作,几个月下来,总体上体验还是比较优秀的。

使用现代 C++语言标准

自 C++11 标准推出以来,现代 C++ 标准已发展到 C++20。许多新特性和标准库改进极大地提升了开发体验、代码简洁性和程序安全性。例如:

  • 自动类型推导 (auto) 减少了复杂类型声明的代码;
  • 智能指针降低了内存安全问题的风险;
  • 函数对象和 lambda 表达式带来了类函数式编程的体验;
  • thread、range 等许多实用的标准库;

合理使用设计模式

作为典型的面向对象语言,在 C++中适当地使用设计模式有助于编写可重用、可维护和可扩展的代码。比较有用的设计模式有:单例模式、工厂模式和抽象工厂模式、建造者模式、策略模式、命令模式等。

值得注意的是,许多设计模式需要区分接口类和实现类。通常在 C++ 中,通过声明一个 virtual 的虚构函数来定义一个抽象基类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <memory>
#include <string>
#include <sstream>

class IDisplay {
public:
virtual std::string toString() = 0;
virtual ~IDisplay() {}
};

class Message : public IDisplay {
public:
std::string content;
Message(std::string content) : content(content) {}
std::string toString() override {
std::ostringstream os;
os << "Message(" << content << ")";
return os.str();
}
};

int main() {
std::unique_ptr<IDisplay> obj = std::make_unique<Message>("ok");
std::cout << obj->toString() << std::endl;
return 0;
}

Read more »

随着持续的版本演进,VS Code 的功能也越来越多,其中一个比较好用的功能是 VS Code 配置(VS Code Profiles)。

Visual Studio Code有数百种设置、数千种扩展和无数种调整UI布局的方法来自定义编辑器。VS Code Profiles允许您创建自定义设置,并在它们之间快速切换或与他人共享。

VS Code 配置总体上使用比较简单,可以参考官方文档

Read more »

目前最常见的运行大语言模型的方式是使用 Python 的transformers库。只需要数行代码就可以加载并运行诸多 hugingface 平台上托管的语言模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from transformers import AutoTokenizer
import transformers
import torch

model = "meta-llama/Llama-2-7b-chat-hf"

tokenizer = AutoTokenizer.from_pretrained(model)
pipeline = transformers.pipeline(
"text-generation",
model=model,
torch_dtype=torch.float16,
device_map="auto",
)

sequences = pipeline(
'I liked "Breaking Bad" and "Band of Brothers". Do you have any recommendations of other shows I might like?\n',
do_sample=True,
top_k=10,
num_return_sequences=1,
eos_token_id=tokenizer.eos_token_id,
max_length=200,
)
for seq in sequences:
print(f"Result: {seq['generated_text']}")

不过使用 transformers 库还是有一些先决条件的,包括:

  • 配置 Python 虚拟环境;
  • 安装 pytorch 库;
  • 安装 cuda 环境等;

Mozilla 团队推出了一个新项目llamafile,可以使用单个文件分发并运行大语言模型。

下载 llamafile 模型文件

llamafile项目的github主页上提供了若干个不同规模的语言模型的llamafile格式文件下载链接,我选择的是LLaVa 1.5,参数规模适中(3.97GB),能够运行在家里8G显存的PC上,并且本身是一个多模态模型,可以分析图片。

models

Read more »

上个季度加入了公司的 AI 团队,负责的工作除了常规的服务端开发之外,还包括了在端上运行机器学习模型。考虑到性能因素,没有使用 Python 或 Node.js 等运行时,而是直接使用 C++来执行模型推理逻辑。在这里分享一些经验和教训。

模型格式

我们使用的模型格式是 onnx。onnx 是一种开放的模型格式,使用一个二进制文件存储模型的结构和参数,可以在不同的平台上使用不同的运行时加载和执行。目前主流的深度学习框架都支持导出 onnx 模型,例如 PyTorch、TensorFlow 等。

模型运行时

对于常见的网络结构的模型,可以使用 OpenCV 的 dnn 模块来加载和执行。OpenCV 是一个开源的计算机视觉库,提供了很多计算机视觉相关的功能,其中 dnn 模块提供了加载和执行深度学习模型的功能。

对于一些使用了自定义算子的模型,OpenCV 的 dnn 模块可能无法加载,这时候可以使用 onnxruntime 来加载和执行模型。onnxruntime 是微软开源的一个 onnx 运行时,支持加载和执行 onnx 模型,支持 CPU 和 GPU 加速。小小的吐槽一下,与 Python 的 onnxruntime sdk 相比,C++ 的 onnxruntime sdk 的接口有够难用。

Windows 上使用 onnxruntime 的一个坑

Windows 10 和 Windows 11 在系统库里内置了一个较旧版本的 onnx runtime,如果使用了较新的 onnxruntime,可能会出现加载模型失败的问题。一个解决方式是在代码中指定加载动态链接库的路径,并通过 onnx runtime 的 api 指定加载的版本。

1
2
3
4
5
6
7
8
9
10
11
12
#include "Windows.h"
#define ORT_API_MANUAL_INIT // 定义这个宏可以禁止 onnxruntime 自动加载
#include <onnxruntime_cxx_api.h>

int main(){
auto mod = LoadLibrary(L"onnxruntime1.16.1.dll");
auto OrtGetApiBase =
(const OrtApiBase *(*)(void))GetProcAddress(mod, "OrtGetApiBase");
Ort::InitApi(OrtGetApiBase()->GetApi(ORT_API_VERSION));

// ...
}
Read more »