nixos 更新 flake
flakes 的设计初衷是“重现性”(Reproducibility),而不是“实时性”。
获取最新的分支构建信息
# 只更新 nixpkgs 这个 input
nix flake update nixpkgs
# 或者更新所有 inputs
nix flake update
注意,建议更新所有 inputs,不然可能会出现 nixpkgs 和 home-manager 版本不一致的问题
flakes 的设计初衷是“重现性”(Reproducibility),而不是“实时性”。
# 只更新 nixpkgs 这个 input
nix flake update nixpkgs
# 或者更新所有 inputs
nix flake update
注意,建议更新所有 inputs,不然可能会出现 nixpkgs 和 home-manager 版本不一致的问题
# 删除所有 7 天前的旧世代(Generations)
sudo nix-collect-garbage --delete-older-than 7d
在 nixos 配置中添加:
# Setup Clash
programs.clash-verge = {
enable = true;
serviceMode = true;
tunMode = true;
};
开启了 tunMode 和 serviceMode
Share 目前还是可以使用的,本文介绍如何使用 surge modules 来激活。
11111111-2222-3333-4444-555555555555 即可激活。
当我在 cronjob 中设置:LOGSEQ_FOLDER=$HOME/logseq 时 (这个语法会被 cronjob 设置为环境变量),在后续的命令调用 LOGSEQ_FOLDER 这个变量的时候,并不能正确的获取到 $HOME 变量。但是我们可以尝试在 SHELL 中运行命令export LOGSEQ_FOLDER=$HOME/logseq,然后从环境变量中查找 env|grep LOGSEQ_FOLDER 得到结果是:/home/alex/logseq, 为什么?
因为 cronjob 中不会对环境变量的值 $HOME 二次展开,但是 shell 中,是直接展开了的!
LOGSEQ_FOLDER=$HOME/logseq 表示的是一个键值对,原样放入子进程的模块的环境变量中。LOGSEQ_FOLDER=$HOME/logseq 表示的是一个表达式,会先计算,再展开,所以你 export 后的环境变量就已经是展开过后的了。在 windows 下的手机连接有时候会报错:"Microsoft 手机连接 - 无法连接到你的 Android 设备,因为你正在尝试访问中国以外的应用程序,目前我们不支持漫游区域。"
只需要添加对应的 "dcg.microsoft.com" 为直连即可。
以 Bitwarden 为例:
ls -la /Applications/ | grep -i bitwarden
spctl -a -t exec -vvv /Applications/Bitwarden.app
输出如下:
/Applications/Bitwarden.app: accepted
source=Notarized Developer ID
origin=Developer ID Application: 8bit Solutions LLC (LTZ2PFU5D6)
如果 source 是 Mac App Store, 那就是通过 app store 下载的,反之如果 source 是 Notarized Developer ID, 那就是通过 DMG 下载的。
这个命令是 macOS 系统中用于 Gatekeeper(门禁)安全机制的 spctl 工具的一个用法。具体解释如下:
spctl -a -t exec -vvv /Applications/Bitwarden.app
spctl
是 macOS 自带的命令行工具,全称是 System Policy Control,用于管理系统策略,尤其是 Gatekeeper 对应用程序的验证和授权。
-a(或 --assess)
表示“评估”(assess)指定的项目,即检查该应用是否被系统策略允许运行。
-t exec(或 --type execute)
指定评估类型为“可执行”(executable),即检查该应用是否可以被当作可执行程序运行。这是针对应用程序(.app)的标准类型。
-vvv
表示输出详细(verbose)信息,v 越多,输出越详细。-vvv 是非常详细的输出,会显示签名信息、证书链、权限来源等。
/Applications/Bitwarden.app
要评估的目标应用程序路径,这里是安装在应用程序文件夹中的 Bitwarden 密码管理器。
检查 Bitwarden.app 是否通过了 macOS 的 Gatekeeper 验证,是否被允许运行。
运行后,你会看到类似这样的输出(取决于实际情况):
/Applications/Bitwarden.app: accepted
source=Apple Notarized Developer ID
origin=Developer ID Application: Bitwarden Inc. (XXXXX)
在 /etc/nixos/configuration 中这样配置即可:
services.interception-tools =
let
itools = pkgs.interception-tools;
itools-caps = pkgs.interception-tools-plugins.caps2esc;
in
{
enable = true;
plugins = [ itools-caps ];
# requires explicit paths: https://github.com/NixOS/nixpkgs/issues/126681
udevmonConfig = pkgs.lib.mkDefault ''
- JOB: "${itools}/bin/intercept -g $DEVNODE | ${itools-caps}/bin/caps2esc -m 1 | ${itools}/bin/uinput -d $DEVNODE"
DEVICE:
EVENTS:
EV_KEY: [KEY_CAPSLOCK, KEY_ESC]
'';
};
参考连接:https://discourse.nixos.org/t/best-way-to-remap-caps-lock-to-esc-with-wayland/39707/6
logseq 中 api 返回的 uuid 在真实的 block 中未必会有,需要检查是否有 id 这个属性才能够正确获取到:
def ensure_uuid_property(self, blocks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
updated_blocks = []
for block in blocks:
if 'properties' not in block or 'id' not in block['properties']:
# Logseq block UUID is typically in block['uuid']
block_uuid = block.get('uuid')
if block_uuid:
print(f"Ensuring uuid property for block: {block_uuid}")
self.upsert_block_property(block_uuid, "id", block_uuid)
# Update the block in memory for consistency
if 'properties' not in block:
block['properties'] = {}
block['properties']['id'] = block_uuid
updated_blocks.append(block)
return updated_blocks
使用本地 embddings 遇到如下问题:
qwen3_embdings = OpenAIEmbeddings(
model="text-embedding-qwen3-embedding-0.6b",
base_url="http://127.0.0.1:1234/v1",
)
运行时报错:
Traceback (most recent call last):
File "/Users/zhaochunqi/ghq/github.com/zhaochunqi/ai-agents-learning/main.py", line 20, in <module>
_ = vector_store.add_documents(documents=all_splits)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/zhaochunqi/ghq/github.com/zhaochunqi/ai-agents-learning/.venv/lib/python3.12/site-packages/langchain_core/vectorstores/in_memory.py", line 195, in add_documents
vectors = self.embedding.embed_documents(texts)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/zhaochunqi/ghq/github.com/zhaochunqi/ai-agents-learning/.venv/lib/python3.12/site-packages/langchain_openai/embeddings/base.py", line 590, in embed_documents
return self._get_len_safe_embeddings(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/zhaochunqi/ghq/github.com/zhaochunqi/ai-agents-learning/.venv/lib/python3.12/site-packages/langchain_openai/embeddings/base.py", line 480, in _get_len_safe_embeddings
response = self.client.create(
^^^^^^^^^^^^^^^^^^^
File "/Users/zhaochunqi/ghq/github.com/zhaochunqi/ai-agents-learning/.venv/lib/python3.12/site-packages/openai/resources/embeddings.py", line 132, in create
return self._post(
^^^^^^^^^^^
File "/Users/zhaochunqi/ghq/github.com/zhaochunqi/ai-agents-learning/.venv/lib/python3.12/site-packages/openai/_base_client.py", line 1259, in post
return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/zhaochunqi/ghq/github.com/zhaochunqi/ai-agents-learning/.venv/lib/python3.12/site-packages/openai/_base_client.py", line 1047, in request
raise self._make_status_error_from_response(err.response) from None
openai.BadRequestError: Error code: 400 - {'error': "'input' field must be a string or an array of strings"}
添加 check_embedding_ctx_length 参数即可
qwen3_embdings = OpenAIEmbeddings(
model="text-embedding-qwen3-embedding-0.6b",
base_url="http://127.0.0.1:1234/v1",
check_embedding_ctx_length=False, # 关键:禁用长度检查以兼容 LM Studio
)
原因是这个参数默认 True, LangChain 会检查输入文本是否超过模型的最大上下文长度,如果文本太长,会被分割成多个 chunk,这样向 api 发送的是 token 数组,不是原始的字符串。
True) - 会出错的流程:# 输入:"Hello world"
# 1. tiktoken 处理:[15496, 1917] (token IDs)
# 2. API 请求:{"input": [15496, 1917], "model": "..."}
# 3. LM Studio 收到整数数组,报错:"'input' field must be a string"
False 后 - 正常的流程:# 输入:"Hello world"
# 1. 直接发送:{"input": "Hello world", "model": "..."}
# 2. LM Studio 收到字符串,正常处理