包含关键字 typecho 的文章

数据主权时代:为何选择本地知识库

在信息爆炸的今天,我们每天都在产生和接触海量的知识文件。从PDF报告到Word文档,从产品图片到会议视频,这些数字资产构成了个人和企业智慧的核心。然而,当我们将这些宝贵的数据交给云端服务时,是否曾想过:我们的知识安全吗?

云端困境与本地解决方案

传统的云知识库确实提供了便利,但背后隐藏着数据泄露和AI白嫖的风险。企业核心数据、个人研究成果,这些本应受到严格保护的知识资产,在云端面临着不可控的安全威胁。

访答本地知识库的出现,正是对这一困境的回应。它让知识管理回归本地,所有操作都在用户自己的电脑上进行,不上传任何文件数据。这种设计理念体现了对数据主权的尊重——你的知识,应该由你做主。

深度解析:超越传统搜索

与传统搜索工具不同,访答本地知识库具备深度解析能力。它不仅能处理文本内容,还能理解图片中的文字、视频中的场景、表格中的数据关系。这种多模态的理解能力,使得搜索和问答更加精准和智能。

想象一下:当你在海量文件中寻找某个特定印章出现过的所有合同,或者需要找出所有包含某张产品图片的演示文稿时,传统的关键词搜索往往无能为力。而访答的知识库却能通过深度解析,轻松完成这些复杂任务。

安全与智能的平衡

在人工智能时代,我们既渴望智能化的知识管理,又担忧数据安全。访答本地知识库在这两者间找到了平衡。它支持多种AI模型,包括DeepSeek、Qwen等,但这些模型都在本地运行,确保敏感数据不会外泄。

对于政企单位而言,这种平衡尤为重要。内部培训资料、技术文档、销售数据等核心资产,既需要高效的检索和智能问答,又必须保证绝对的安全。本地知识库正是满足这一需求的理想选择。

未来的知识管理方向

随着数据隐私意识的增强,本地化、可控化的知识管理将成为趋势。访答本地知识库不仅是一个工具,更代表了一种理念:在享受AI带来的便利时,我们不应以牺牲数据安全为代价。

无论是个人用户保护自己的知识产出,还是企业守护核心数据资产,选择本地知识库都是迈向智能化管理的明智之举。在这个数据即资产的时代,保护好我们的知识,就是保护我们的未来。

过去 5 年,累计立 flag 想写博客 200+次,实际产出 10+篇。
并不是写不出内容,而是每次想到写完文章后的流程:找图、截图、压缩、传图床、拿链接、写 YAML 头信息……热情就熄灭了一半。


大家好,我是「轻渡(Ferry)」的开发者。

作为Hexo/Hugo/Jekyll的重度用户,我一直觉得现有的写作流程不仅割裂,而且不够优雅。

VS Code 很强,但对静态博客来说配置太繁琐;
Typora 很好,但对 Front Matter 和图床的集成又差点意思。

所以趁着最近有空,我开发了轻渡(Ferry) —— 一个专注于静态博客写作的“闭环”编辑器。

轻渡 App

一、彻底解决“图片焦虑”(这是我最想安利的功能)

写文章时,图片处理是最断节奏的。
轻渡里,我把这个流程压缩到了极致:

  • 拖拽即发布:直接把图片(或剪贴板内容)拖入编辑器,自动完成压缩->上传->回填 Markdown 链接。
  • 独家图床复活术:针对大家常用的“某浪”图床(wb),内置了 403 防盗链修复方案,不再满屏裂图。
  • AI 水印擦除:如果你常用 Google Gemini 生成配图,编辑器能自动识别并擦除 SynthID 水印,让图片更纯净。
  • 无损/有损压缩:支持压缩开关,在画质和体积间自由切换。

二、可视化 Front Matter ,告别 YAML 缩进噩梦

不管是 Hexo 还是 Hugo ,头部元数据(Front Matter)写错一个空格,整个博客渲染就挂了。
轻渡内置了脚手架:

  • 表单式填写:标题、分类、标签、日期全部可视化操作。
  • 模板引擎:支持自定义字段模板,一键生成标准博文结构。

三、本地优先,Git 友好

  • 数据安全:直接挂载你本地的博客 Git 仓库,文件就在你硬盘里,不经过任何第三方云端存储(除了图床)。
  • 一键同步:写完文章,编辑器右上角直接点“同步”,自动完成 git commit+git push 。

其他功能&细节

  • 多引擎适配:完美支持 Hexo/Hugo/Jekyll 目录结构。
  • 沉浸体验:精心调教的深色/浅色模式(珊瑚紫/VS Code/海洋蓝),基于 CodeMirror ,支持 LaTeX 公式、Emoji 快捷输入。
  • 跨平台:macOS(Intel/Apple Silicon)、Windows 、Ubuntu 全覆盖。
  • AI 输出阅读优化:AI 生成的 Markdown 太长、格式太乱看着累?双击用轻渡打开,自动生成侧边目录,条理清晰,当作本地 Markdown 阅读器也很好用。甚至你只需告知 AI 用轻渡打开报告,它便可以轻松打开。

界面预览

界面预览

(图注: 界面预览)

拖拉上传

(图注: 拖拉上传)

可视化 Front Matter

(图注: 可视化 Front Matter )

阅读模式自动打开目录导航

(图注: 阅读模式自动打开目录导航)

关于送码&下载

目前软件处于初期推广阶段,欢迎 V 友们体验反馈。

下载地址:https://github.com/ferry-editor/ferry/releases

项目主页:https://github.com/ferry-editor/ferry/wiki

🎁 送码福利
为了感谢大家的支持,我准备了一批兑换码。

  • 10 枚 6 个月许可证:直接拿码,先到先得(手慢无)
  • 留言 100%获得 3 个月许可证
    留言格式:「你的博客引擎(Hexo/Hugo...) + 博客地址 + 邮箱(base64 编码)」
    我会在稍后统一发送。

8UA6-VLJH-L3PC-S3HE



LJX9-ZPAQ-FVU2-CTNE



56NF-6WWP-FCRF-PURV



TJBE-AJ96-GUCW-4YXC



5RU5-RDXH-JWN3-LSLW



YMYG-2Y7S-7EGS-8RKL



9ANG-2FRF-RNZB-MMJJ



QVKX-YHAE-DK67-HRKT



ZBMY-3DMW-9G2M-U28V



HZAC-L5WP-VHPX-WEFB

最后

开发不易,功能肯定还有不完善的地方。如果你在使用中遇到 Bug 或有新的需求,欢迎在 GitHub 提 Issue 或直接在帖子下留言,我会持续迭代。

Happy Blogging! ✍️

线程停止

stop方法

stop 方法虽然可以停止线程,但它已经是不建议使用的废弃方法了,这一点可以通过 Thread 类中的源码发现,stop 源码如下:

stop 方法是被 @Deprecated 修饰的不建议使用的过期方法,并且在注释的第一句话就说明了 stop 方法为非安全的方法。

原因在于它在终止一个线程时会强制中断线程的执行,不管run方法是否执行完了,并且还会释放这个线程所持有的所有的锁对象。这一现象会被其它因为请求锁而阻塞的线程看到,使他们继续向下执行。这就会造成数据的不一致。

比如银行转账,从A账户向B账户转账500元,这一过程分为三步,第一步是从A账户中减去500元,假如到这时线程就被stop了,那么这个线程就会释放它所取得锁,然后其他的线程继续执行,这样A账户就莫名其妙的少了500元而B账户也没有收到钱。这就是stop方法的不安全性。

设置标志位

如果线程的run方法中执行的是一个重复执行的循环,可以提供一个标记来控制循环是否继续

class FlagThread extends Thread {
    // 自定义中断标识符
    public volatile boolean isInterrupt = false;
    @Override
    public void run() {
        // 如果为 true -> 中断执行
        while (!isInterrupt) {
            // 业务逻辑处理
        }
    }
}

但自定义中断标识符的问题在于:线程中断的不够及时。因为线程在执行过程中,无法调用 while(!isInterrupt) 来判断线程是否为终止状态,它只能在下一轮运行时判断是否要终止当前线程,所以它中断线程不够及时,比如以下代码:

class InterruptFlag {
    // 自定义的中断标识符
    private static volatile boolean isInterrupt = false;

    public static void main(String[] args) throws InterruptedException {
        // 创建可中断的线程实例
        Thread thread = new Thread(() -> {
            while (!isInterrupt) { // 如果 isInterrupt=true 则停止线程
                System.out.println("thread 执行步骤1:线程即将进入休眠状态");
                try {
                    // 休眠 1s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread 执行步骤2:线程执行了任务");
            }
        });
        thread.start(); // 启动线程

        // 休眠 100ms,等待 thread 线程运行起来
        Thread.sleep(100);
        System.out.println("主线程:试图终止线程 thread");
        // 修改中断标识符,中断线程
        isInterrupt = true;
    }
}

输出:我们期望的是:线程执行了步骤 1 之后,收到中断线程的指令,然后就不要再执行步骤 2 了,但从上述执行结果可以看出,使用自定义中断标识符是没办法实现我们预期的结果的,这就是自定义中断标识符,响应不够及时的问题。

interrupted中断

这种方式需要在while循环中判断使用

使用 interrupt 方法可以给执行任务的线程,发送一个中断线程的指令,它并不直接中断线程,而是发送一个中断线程的信号,把是否正在中断线程的主动权交给代码编写者。相比于自定义中断标识符而然,它能更及时的接收到中断指令,如下代码所示:

public static void main(String[] args) throws InterruptedException {
    // 创建可中断的线程实例
    Thread thread = new Thread(() -> {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("thread 执行步骤1:线程即将进入休眠状态");
            try {
                // 休眠 1s
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("thread 线程接收到中断指令,执行中断操作");
                // 中断当前线程的任务执行
                break;
            }
            System.out.println("thread 执行步骤2:线程执行了任务");
        }
    });
    thread.start(); // 启动线程

    // 休眠 100ms,等待 thread 线程运行起来
    Thread.sleep(100);
    System.out.println("主线程:试图终止线程 thread");
    // 修改中断标识符,中断线程
    thread.interrupt();
}

输出:

从上述结果可以看出,线程在接收到中断指令之后,立即中断了线程,相比于上一种自定义中断标识符的方法来说,它能更及时的响应中断线程指令。

利用interruptedException

这种方式 不 需要在while循环中判断使用

如果线程因为执行join(),sleep或者wait()而进入阻塞状态,此时想要停止它,可以调用interrupt(),程序会抛出interruptedException异常。可以利用这个异常终止线程

public void run() {
    System.out.println(this.getName() + "start");
    int i=0;
    //while (!Thread.interrupted()){
    while (!Thread.currentThread().isInterrupted()){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            //e.printStackTrace();
            System.out.println("中断线程");
            break;//通过识别到异常来中断
        }
        System.out.println(this.getName() + " "+ i);
        i++;
    }
    System.out.println(this.getName() + "end");
}

Executor 的中断操作

调用 Executor 的 shutdown() 方法会等待线程都执行完毕之后再关闭,但是如果调用的是 shutdownNow() 方法,则相当于调用每个线程的 interrupt() 方法。

以下使用 Lambda 创建线程,相当于创建了一个匿名内部线程。

public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(() -> {
        try {
            Thread.sleep(2000);
            System.out.println("Thread run");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    executorService.shutdownNow();
    System.out.println("Main run");
}
Main run
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at ExecutorInterruptExample.lambda$main$0(ExecutorInterruptExample.java:9)
    at ExecutorInterruptExample$$Lambda$1/1160460865.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

如果只想中断 Executor 中的一个线程,可以通过使用 submit() 方法来提交一个线程,它会返回一个 Future<?> 对象,通过调用该对象的 cancel(true) 方法就可以中断线程。

Future<?> future = executorService.submit(() -> {
    // ..
});
future.cancel(true);

线程之间的协作

当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调。

join()

案例

在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。

对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。

public class JoinExample {

    private class A extends Thread {
        @Override
        public void run() {
            System.out.println("A");
        }
    }

    private class B extends Thread {

        private A a;

        B(A a) {
            this.a = a;
        }

        @Override
        public void run() {
            try {
                a.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B");
        }
    }

    public void test() {
        A a = new A();
        B b = new B(a);
        b.start();
        a.start();
    }
}
public static void main(String[] args) {
    JoinExample example = new JoinExample();
    example.test();
}
A
B

原理

public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        while (isAlive()) {//检查线程是否存活,只要线程还没结束,主线程就会一直阻塞
            wait(0);//这里的wait调用的本地方法。
        }
    } else {//等待一段指定的时间
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

从源码来看,实际上join方法就是调用了wait方法来使得线程阻塞,一直到线程结束运行。注意到,join方法前的synchronized修饰符,它相当于:

public final void join(long millis){
 synchronized(this){
        //代码块
    }
}

也就是说加锁的对象即调用这个锁的线程对象,在main()方法中即为t1,持有这个锁的是主线程即main()方法,也就是说代码相当于如下:

//t1.join()前的代码
synchronized (t1) {
 // 调用者线程进入 t1 的 waitSet 等待, 直到 t1 运行结束
 while (t1.isAlive()) {
  t1.wait(0);
 }
}
//t1.join()后的代码

也因此主线程进入等待队列,直到 t1 线程结束。

这里可能会有很多人会有疑惑,为什么t1.wait了,阻塞的不是t1,而是主线程?

实际上,如果要阻塞t1,那么就应该在t1的run 方法里进行阻塞,如在run方法里写wait();(当然还有suspend方法,这属于非Java层面,另说)

而这里的 wait 方法被调用以后,是让持有锁的线程进入等待队列,即主线程调用,因此 t1 线程并不会被阻塞,阻塞的是主线程。

也就是说,join方法是一个同步方法,当主线程调用t1.join()方法时,主线程先获得了t1对象的锁,随后进入方法,调用了t1对象的wait()方法,使主线程进入了t1对象的等待池。

那么问题在于,这里只看到了wait方法,却并没有看到notify或者是notifyAll方法,那么主线程在那里被唤醒呢?

这里参考jvm的代码:

static void ensure_join(JavaThread* thread) {

 Handle threadObj(thread, thread->threadObj());

 ObjectLocker lock(threadObj, thread);

 hread->clear_pending_exception();

 //这一句中的TERMINATED表示这是线程结束以后运行的
 java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);

    //这里会清楚native线程,isAlive()方法会返回false
    java_lang_Thread::set_thread(threadObj(), NULL);

 //thread就是当前线程,调用这个方法唤醒等待的线程。
 lock.notify_all(thread);

 hread->clear_pending_exception();

}

其实是jvm虚拟机中存在方法lock.notify_all(thread),在t1线程结束以后,会调用该方法,最后唤醒主线程。

所以简化一下,流程即:

wait() notify() notifyAll()

调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。

它们都属于 Object 的一部分,而不属于 Thread。

只能用在同步方法synchronized或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateExeception。

使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。

public class WaitNotifyExample {
    public synchronized void before() {
        System.out.println("before");
        notifyAll();
    }

    public synchronized void after() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after");
    }
}
public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    WaitNotifyExample example = new WaitNotifyExample();
    executorService.execute(() -> example.after());
    executorService.execute(() -> example.before());
}
before
after

wait() 和 sleep() 的区别

  • wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法;
  • wait() 会释放锁,sleep() 不会。

await() signal() signalAll()

java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活。

使用 Lock 来获取一个 Condition 对象。

public class AwaitSignalExample {
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void before() {
        lock.lock();
        try {
            System.out.println("before");
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void after() {
        lock.lock();
        try {
            condition.await();
            System.out.println("after");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    AwaitSignalExample example = new AwaitSignalExample();
    executorService.execute(() -> example.after());
    executorService.execute(() -> example.before());
}
before
after

线程中的异常处理

Runnable中异常如何被吞掉

Runnable 接口的 run() 方法不允许抛出任何被检查的异常(checked exceptions),只能处理或抛出运行时异常(unchecked exceptions)。当在 run() 方法内发生异常时,如果没有显式地捕获和处理这些异常,它们通常会在执行该 Runnable 的线程中被“吞掉”,即异常会导致线程终止,但不会影响其他线程的执行。

public void uncaughtException(Thread t, Throwable e) {
   if (parent != null) {
        parent.uncaughtException(t, e);
   } else {
        Thread.UncaughtExceptionHandler ueh =
            Thread.getDefaultUncaughtExceptionHandler();
        if (ueh != null) {
            ueh.uncaughtException(t, e);
        } else if (!(e instanceof ThreadDeath)) {
            System.err.print("Exception in thread \""
                             + t.getName() + "\" ");
            e.printStackTrace(System.err);
        }
    }
}

解决方案:

  1. 在run方法中显示的捕获异常

    public void run() {
        try {
            // 可能抛出异常的代码
        } catch (Exception e) {
            // 记录日志或处理异常
            throw new RuntimeException(e);
        }
    }
  2. 为创建的线程设置一个UncaughtExceptionHandler

    Thread t = new Thread(() -> {
       int i = 1 / 0;
    }, "t1");
    t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
       @Override
       public void uncaughtException(Thread t, Throwable e) {
            logger.error('---', e);
       }
    });
  3. 使用Callable代替RunnableCallablecall方法允许抛出异常,然后可以通过提交给ExecutorService返回的Future来捕获和处理这些异常

    ExecutorService executor = Executors.newFixedThreadPool(1);
    Future<?> future = executor.submit(() -> {
        // 可能抛出异常的代码
    });
    
    try {
        future.get(); // 这里会捕获到Callable中的异常
    } catch (ExecutionException e) {
        Throwable cause = e.getCause(); // 获取原始异常
    }

Callable中异常如何被吞掉

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("===> 开始执行callable");
        int i = 1 / 0; //异常的地方
        return "callable的结果";
    }
}

public class CallableAndRunnableTest {

    public static void main(String[] args) {
        System.out.println(" =========> main start ");
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));
        Future<String> submit = threadPoolExecutor.submit(new MyCallable());
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(" =========> main end ");
    }
}

运行结果

 =========> main start 
 ===> 开始执行callable
 =========> main end 

源码如下:

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

RunableFuture<T> 是个接口,但是它继承了Runnable 接口 , 实现类是 FutureTask ,因此就需要看下 FutureTask里的run方法 是不是和 构造时的Callable 有关系:

public void run() {
     // 状态不属于初始状态的情况下,不进行后续逻辑处理
     // 那也就是run 方法只能执行一次
     if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                   null, Thread.currentThread()))
        return;
    try { 
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            // 
            boolean ran;
            try {
                // 执行 Callable 里的 call 方法 ,将结果存入result变量中
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                 // call 方法异常 , 记录下异常结果
                setException(ex);
            }
            // call 方法正常执行完毕 ,进行结果存储
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

接下来就要看,如果存储正常结果的set(result)方法 和存储异常结果的 setException(ex) 方法

protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion();
    }
}

protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

这两个代码都做了一个操作,就是将正常结果result 和 异常结果 exception 都赋值给了 outcome 这个变量 。

接着再看下future的get方法

//这里有必须看下Task的结束时的状态,如果正常结束,状态为 NORMAL , 异常结果,状态为EXCEPTIONAL 。 看下几个状态的定义,如下:  
private volatile int state;
private static final int NEW          = 0;
private static final int COMPLETING   = 1;
private static final int NORMAL       = 2;
private static final int EXCEPTIONAL  = 3;
private static final int CANCELLED    = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED  = 6;

/**
* @throws CancellationException {@inheritDoc}
*/
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    // NORMAL(2) 、EXCEPTIONAL(3) 都大于 COMPLETING(1),所以Task结束之后,不会走该if
    if (s <= COMPLETING)
         s = awaitDone(false, 0L);
    // 重点: 返回结果
    return report(s);
}

private V report(int s) throws ExecutionException {
    // 之前正常结果或者异常都存放在Object outcomme 中了
    Object x = outcome;
    // 正常返回
    if (s == NORMAL)
        return (V)x;
    // EXCEPTIONAL(3) 小于 CANCELLED(4) ,所以不会走该if分支,直接后续的throw 抛异常的逻辑
    if (s >= CANCELLED)
        throw new CancellationException();
    // 不等于NORMAL 且 大于等于 CANCELLED  ,  再结合 调用 report(int s ) 之前也做了state 的过滤
    //到这一步,那只能是EXCEPTIONAL(3) 
    throw new ExecutionException((Throwable)x);
}

因此可以通过get方法获取到异常结果

去年出行买了机票,结果被多收了 104,实际 390 的机票,平台 494 卖给我,忍不了一点,直接收集材料起诉,前后花了几个月,因为是第一次起诉,很多东西不知道,时间花在材料收集和等待审核(诉讼太多了)。
需要材料:
**双方的服务合同(用户服务协议)及完整订单、平台账号实名信息截图(未显示实名信息只显示绑定手机的,应一并提交该手机号实名认证的证据,如话费发票)、含实名的支付流水、被告身份信息(国家企业信用信息网截图)。 **

需要在对方注册地提起诉讼,我这里是北京,所以直接在北京互联网法院提起诉讼,现在统一到:人民法院在线服务网 https://zxfw.court.gov.cn/zxfw/

image
立案信息

最终和解了,因为对方法务强大,会钻空子,只好拿和解费撤诉了。

原文: https://mp.weixin.qq.com/s/-d2u6Ldy7STv-koO4kk7eg

前情提要:北京联通家宽公网 IPv4+IPv6 ,有一台自建服务器主要用来跑 Minecraft 和一些网页(通过 Cloudflared)

我有些文件(3~10G 每个)要保持可下载的状态,需求量不是很大。我是用 BT 做种+OneDrive ,但 OneDrive 在国内经常直连不上,最近有个朋友说他受不了他用的网盘了老是挂,然后提议拉几个人一起做种。
qbit(图中下载比较慢的是一个香港的 peer ,宽带目前还是正常的)

现在种子互相分享完了来 V 站看了几个用 PT 被限速的例子有点担心,想请教各位大佬有没有更合适的方案适应我的需求,或者如果我这么用的话要注意什么来降低被限速的风险。

(2026.01.18-02.01)🚀 好虫子周刊:DeepSeek V4前瞻、Agent标准确立、音频界面革命

本周关键词: 混合专家 (MoE)、Agent 技能标准、物理 AI、音频首选 (Audio-first)

摘要: 本周是开源界深度复盘与大厂战略转向的关键交汇期。DeepSeek R1 发布周年之际,官方以 86 页超长报告披露了 RL 训练核心机密,并预告 V4 版本将冲击 Claude 代码王座。与此同时,Anthropic 推动的 Agent Skills 规范逐渐成为行业事实标准,OpenAI 亦被传出转向“音频优先”硬件策略。整体趋势显示,AI 正在从“大参数”竞赛转向“高可靠性 Agent”和“低成本推理”的务实阶段。

🚨 核心头条 (Top Stories)

1核心头条

1. DeepSeek R1 报告更新与 V4 预告:开源界的透明化巅峰

  • 发布时间: 01.20
  • 核心亮点: DeepSeek 将 R1 技术报告扩展至 86 页,完整披露了从 Dev1 到 Dev3 的三阶段强化学习(RL)路径。同时预告 V4 版本将于 2 月中旬发布。
  • 技术突破: 详细记录了 MCTS(蒙特卡洛树搜索)在训练中的失败经验,证明了纯 RL 训练即可实现推理能力涌现。V4 将采用更优化的 MoE 架构,侧重软件工程能力。
  • 开源/行业价值: 为全球开发者节省了数亿元的验证算力,奠定了中国开源模型在 Hugging Face 社区的领导地位。

2. Agent Skills 规范确立:智能体从“玩具”走向“工具”

  • 发布时间: 01.26
  • 核心亮点: Anthropic 官方开放 Agent Skills 规范。Moltbot(原 Clawdbot)在 GitHub 狂揽 10 万 Star,成为增长最快的 AI 助手项目。
  • 技术突破: 通过 MCP(Model Context Protocol)将智能体与真实系统连接摩擦降至最低。引入自验证机制,解决了复杂任务下 Agent 频繁遗忘上下文的痛点。
  • 开源/行业价值: 标志着 Agent 开发从碎片化走向标准化,开发者可复用 Vercel 或 Anthropic 提供的技能模块,加速企业级智能体部署。

3. 音频界面革命:OpenAI 战略重心向“声音”偏移

  • 发布时间: 01.30
  • 核心亮点: 社区情报显示 OpenAI 计划在 Q1 发布新一代非 Transformer 架构的音频模型,并与 Jony Ive 合作开发“音频优先”个人设备。
  • 技术突破: 实现真·端到端语音交互,摆脱传统的“语音转文字”中转,延迟大幅降低,支持更细腻的情感表达。
  • 开源/行业价值: 预示着 AI 交互将从屏幕端(Screen-based)转向环境音端(Ambient Audio),为可穿戴设备和智能家居开辟新赛道。

🛠️ GitHub 热门开源项目 (Trending Tools)

2GitHub 热门开源项目

本周 GitHub Star 增长最快、开发者关注度最高的项目精选

Moltbot

  • 一句话介绍: 自托管的“最强 AI 智能助手”,GitHub 增长奇迹。
  • 核心价值: 支持集成 Slack/Discord/Telegram,具备系统级操作权限,重点在于数据完全本地化处理,解决了企业对闭环 AI 的核心焦虑。
  • 项目地址: moltbot/moltbot

🤖 OpenClaw

  • 一句话介绍: 专注解决 Agent 稳定性的开源框架。
  • 核心价值: 针对长流程任务进行了“反馈闭环”优化,大幅降低了智能体在多步推理中的出错率(Hallucination Rate)。
  • 项目地址: pipecat-ai/nemotron-january-2026 (NVIDIA 驱动版)

🎨 HunyuanVideo 1.5

  • 一句话介绍: 腾讯开源的“显卡救星”视频生成模型。
  • 核心价值: 仅需 13.6GB 显存即可运行 720p 视频生成,通过 SSTA 稀疏注意力技术实现了 1.87 倍的生成提速。
  • 项目地址: Tencent/HunyuanVideo

📑 前沿研究与行业风向 (Insights)

3前沿研究与行业风向

  • 物理 AI (Physical AI) 与世界模型: 随着 Boston Dynamics 展示全电动 Atlas 机器人的 RL 训练成果,学术界开始转向“物理层面的智能定义”。LeCun 的 World Model 实验室获得 50 亿美元估值,标志着 AI 正在尝试理解物理世界的逻辑而非单纯的概率拟合。
  • 算力能源瓶颈: 马斯克在达沃斯论坛再次预警:电力供应将成为 2026 年 AI 扩张的最大红利障碍。Vistra 等电力巨头通过收购天然气电厂直接对接 AI 数据中心,能源溢价正在重塑 AI 供应链。

✍️ 编辑结语: 本周我们看到了 AI 领域从“堆参数”到“堆逻辑”的结构性转变。开源社区不再盲目跟风,而是通过透明的技术报告和标准化的接口(如 MCP)构建护城河。下周,请密切关注 DeepSeek V4 的定档消息,这可能彻底重写 2026 年的 Coding Agent 竞争格局。

整理:好虫子周刊编辑部 数据来源:GitHub, arXiv, Hugging Face等

本文由mdnice多平台发布

📖 前言

想学编程?Python 是个好选择。语法简单、上手快,数据分析和 AI 都能干。

但很多人第一步就卡住了——装软件。我当年第一次装 Python 也在这个坑里折腾了半天,后来才发现其实挺简单的,只是没人告诉我哪些选项该勾、哪些不该勾。

今天就把这个过程写清楚,每一步都有图,跟着做就行。

预计时间: 10-15 分钟


🎯 你会学到

  • 怎么下载 Python 安装包
  • 安装时哪些选项必须勾
  • 怎么检查装没装好
  • 环境变量是个啥、怎么配
  • pip 怎么用

🔧 准备工作

系统要求:

项目要求
系统Windows 10 或 11
类型64 位(现在基本都是)
空间500MB 够了
网络需要联网下安装包

需要准备的:

  • 能上网
  • 管理员权限(装软件需要)

📝 开始装

第一步:下载安装包

1.1 去官网下

打开浏览器,输入:https://www.python.org/downloads/

进去后能看到一个黄色大按钮,上面写着最新的版本号(目前是 3.13.x)。点它就开始下载。

Python官网下载页面
图1:官网下载页面

1.2 选对版本

官网一般会自动识别你的系统,推荐对应的版本。你也可以手动选:

  • Windows installer (64-bit):64 位系统选这个
  • Windows installer (32-bit):32 位系统选这个
不确定自己系统是 32 位还是 64 位?右键「此电脑」→「属性」,在「设备规格」里能看到「系统类型」。

1.3 官网太慢?用这个

官网有时候下载很慢,我传了个网盘:

网盘链接: https://pan.quark.cn/s/7186f4aa4c10

里面是 Python 3.13.0 的 Windows 64 位安装包,直接下就行。

下载后的安装包
图2:安装包文件


第二步:安装

2.1 右键管理员运行

找到刚下的安装包(文件名类似 python-3.13.0-amd64.exe),右键,选「以管理员身份运行」。

右键管理员运行
图3:右键选择管理员运行

⚠️ 一定要管理员运行,不然可能权限不够。

2.2 这一步最关键

安装程序打开后,第一个界面有个选项必须勾:

  • Add Python 3.13 to PATH

安装向导
图4:记得勾选 "Add Python 3.13 to PATH"

为啥要勾这个?

勾了之后,你才能在任何地方(命令提示符、PowerShell)直接敲 python 运行程序。不勾的话,每次都要输入完整路径,特别麻烦。

我当时第一次装就没勾,后来又折腾了半天环境变量。你记得勾上,就省事了。

然后选安装方式:

  • Install Now:默认安装,新手选这个
  • Customize installation:自定义安装,想自己选的用这个

新手直接「Install Now」就行。

2.3 自定义选项(可选)

如果你选了「Customize installation」,会看到这些:

Optional Features:

  • Documentation:官方文档
  • pip:包管理工具(必勾
  • tcl/tk and IDLE:自带的开发环境
  • Python test suite:测试套件
  • py launcher:启动器

建议: 至少勾 pippy launcher,其他的可以不勾。

自定义安装选项
图5:自定义选项

点「Next」继续。

2.4 高级选项(可选)

接下来是「Advanced Options」:

  • Install for all users:给所有用户装(推荐)
  • Associate files with Python:.py 文件关联到 Python(推荐)
  • Create shortcuts:创建快捷方式(推荐)
  • Add Python to environment variables:加到环境变量(如果前面没勾 PATH,这里一定要勾)
  • Precompile standard library:预编译(能快一点)

高级选项
图6:高级选项

安装路径:

默认是 C:\Users\你的用户名\AppData\Local\Programs\Python\Python313\

你可以改成 D:\Python313\ 这样好找的路径。

2.5 开始装

点「Install Now」或「Install」,安装程序开始干活:

  • 复制文件
  • 配置系统
  • 注册环境变量
  • 装 pip 等工具

安装中
图7:安装进度

等 2-5 分钟,别关。

2.6 装好了

看到「Setup was successful」就 OK 了!

安装成功
图8:安装成功

点「Close」关闭。

到这一步,Python 就装好了。


第三步:检查装没装好

装完最好验证一下。

3.1 打开命令提示符

方法一:Win + R

  1. Win + R
  2. 输入 cmd
  3. 回车

运行对话框
图9:Win+R 打开命令提示符

方法二:搜索栏

  1. 点任务栏搜索
  2. 输入 cmd 或「命令提示符」
  3. 点搜索结果

3.2 看看版本

在命令提示符里输入:

python --version

回车。

正常的话会显示:

Python 3.13.0

查看版本
图10:查看 Python 版本

3.3 检查 pip

pip 是装第三方库用的,输入:

pip --version

正常会显示:

pip 24.x.x from ... (python 3.13)

3.4 试一下 Python 环境

想玩玩?输入:

python

提示符会变成 >>>,说明进到 Python 环境了。

试试你的第一行代码:

print("Hello, Python!")

回车,屏幕会显示:

Hello, Python!

恭喜,你的第一行 Python 代码跑起来了!🎉

想退出,输入 exit() 或者按 Ctrl + Z 再回车。


第四步:配置环境变量(如果需要)

如果你在 2.2 勾选了 "Add Python to PATH",这步跳过!

但如果安装时忘了勾,或者命令提示符显示「'python' 不是内部或外部命令」,就需要手动配。

4.1 找到安装路径

默认路径一般是:

  • C:\Users\你的用户名\AppData\Local\Programs\Python\Python313\
  • 或者你自己设的路径

记下来,后面要用。

4.2 打开环境变量设置

  1. 右键「此电脑」→「属性」
  2. 在「关于」页点「高级系统设置」
  3. 在「系统属性」窗口点「环境变量」

4.3 编辑 Path

在「环境变量」窗口,找到「系统变量」里的 Path,双击。

点「新建」,加这两条(按你的实际路径改):

C:\Users\你的用户名\AppData\Local\Programs\Python\Python313\
C:\Users\你的用户名\AppData\Local\Programs\Python\Python313\Scripts\

第二条是给 pip 用的,必须有!

点「确定」保存。

4.4 再验证一遍

关掉命令提示符,重新打开一个,输入:

python --version

这次应该能显示版本号了。


❓ 常见问题

Q1:提示「无法访问 Windows Installer 服务」?

这是 Windows Installer 服务被禁用了。

  1. Win + R,输入 services.msc
  2. 找到「Windows Installer」
  3. 双击,把「启动类型」改成「自动」
  4. 点「启动」,然后「确定」

Q2:输入 python 没反应,打开了应用商店?

Windows 10/11 的一个特性。

试试用 py 命令:

py --version

如果能正常显示,说明 Python 已经装好了,只是 python 命令被应用商店劫持了。你可以:

  1. 在应用商店搜「Python」,卸载应用商店版本
  2. 或者直接用 py 命令(功能一样)

Q3:怎么升级到新版本?

下新版本的安装包,直接装就行。新版本会覆盖旧的,或者你可以保留多个版本。

如果多个版本共存,可以用 py -3.13py -3.12 指定版本。

Q4:pip 装第三方库很慢?

用国内镜像:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名

或者永久配置:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

Q5:找不到 IDLE?

IDLE 是 Python 自带的简易开发环境。如果安装时没勾选:

  1. 重新运行安装程序,选「Repair」或「Modify」
  2. 勾选「tcl/tk and IDLE」
  3. 完成后 IDLE 就会在开始菜单出现

📌 最后说两句

到这里,Python 就装好了。我帮你梳理一下核心步骤:

  1. ✅ 下安装包(官网或网盘)
  2. 安装时记得勾选 "Add Python to PATH"(这个最重要)
  3. ✅ 用命令提示符检查版本
  4. ✅ 试试 Python 交互环境

下一步可以做什么:

  • 学 Python 基础语法(变量、数据类型、循环、函数)
  • 写点小程序(计算器、猜数字)
  • 学用 pip 装第三方库
  • 选个顺手的编辑器(VS Code 或 PyCharm 都不错)

编程这东西,得多练。装好环境只是第一步,后面多写代码、多做项目,慢慢就熟练了。

我第一次装 Python 也踩了不少坑,后来发现其实没啥难的,就是几个选项容易选错。希望能帮你省点时间。

有问题可以留言,我看到会回。


🔗 参考来源


💡 有帮助的话可以收藏,顺便转发给也在学 Python 的朋友~

还没上车~ 2021 16 寸 MacBook m1pro 32g 加 1t

带磕碰卖家卖 7k ,不知道贵了还是便宜了?网上搜大部分在 7500-7800 之间,问下兄弟们值得上车吗?不会我再转手这种要按上千的砍价吧

我的头像

前言

想学 Java?第一步得先把 JDK 装上。

我见过太多新手卡在这一步了:不知道下哪个版本、装完不知道怎么配环境变量、一运行就报错……

今天把 Windows 下装 JDK 17 的完整步骤写出来,每个步骤都有图,跟着做就行。

开始之前

你的电脑得满足这些条件:

  • 系统:Windows 10 或更高
  • 内存:至少留 2GB
  • 硬盘:至少留 500MB

下载安装包有两个办法:

  1. 用我准备的网盘链接(速度更快)
  2. 或者去 Oracle 官网下载:https://www.oracle.com/java/technologies/downloads/

开始安装

步骤一:下载 JDK 17

用网盘下载(推荐)

  1. 打开网盘链接:https://pan.quark.cn/s/7186f4aa4c10
  2. 找到 Windows 版本的安装包(.exe 文件)
  3. 下载到电脑

去 Oracle 官网下载也行

  1. 打开 https://www.oracle.com/java/technologies/downloads/
  2. 选择 Java 17
  3. 选择"Windows x64 Installer"
  4. 下载 .exe 安装包

Oracle 官网下载页面
图1:Oracle 官网下载页面
图片来源:iCode504 个人博客

⚠️ 选对了再下载

  • 一定要选"Windows x64 Installer"
  • 文件名类似 jdk-17_windows-x64_bin.exe

步骤二:运行安装程序

  1. 双击下载好的 .exe 安装包
  2. 会弹出安装向导,点击"下一步"

安装向导界面
图2:JDK 安装向导
图片来源:iCode504 个人博客

  1. 可以选择安装路径

安装路径怎么选?

  • 默认装在 C:\Program Files\Java\jdk-17
  • 想装其他盘也行,比如 D:\Java\jdk-17
  • 注意:路径里别有中文字符

选择安装路径
图3:选择 JDK 安装路径
图片来源:犬小哈教程

  1. 点"下一步",等它装完
  2. 装完后点"关闭"

安装完成
图4:安装完成
图片来源:iCode504 个人博客

步骤三:配置环境变量

装完之后,还得配一下环境变量,让系统知道 JDK 在哪儿。

打开环境变量设置:

  1. Win + R
  2. 输入 sysdm.cpl,回车
  3. 点"高级"选项卡
  4. 点"环境变量"按钮

环境变量设置
图5:环境变量设置入口
图片来源:犬小哈教程

配置 JAVA_HOME 变量:

  1. 在"系统变量"区域,点"新建"
  2. 变量名输入:JAVA_HOME
  3. 变量值输入你的 JDK 安装路径(比如 D:\Java\jdk-17C:\Program Files\Java\jdk-17
  4. 点"确定"

配置 JAVA_HOME
图6:配置 JAVA_HOME 变量
图片来源:iCode504 个人博客

编辑 Path 变量:

  1. 在"系统变量"里找到 Path,双击打开
  2. 点"新建"
  3. 输入:%JAVA_HOME%\bin
  4. 点"确定"保存所有设置

配置 Path 变量
图7:配置 Path 变量
图片来源:iCode504 个人博客

为什么要配置这些?

  • JAVA_HOME:告诉系统 JDK 装在哪儿
  • Path:让系统找得到 java、javac 这些命令

步骤四:验证安装

装完配置好之后,验证一下。

  1. Win + R,输入 cmd,回车
  2. 输入:

    java -version

如果看到类似输出:

java version "17.0.x"
Java(TM) SE Runtime Environment (build 17.0.x+xx)
Java HotSpot(TM) 64-Bit VM (build 17.0.x+xx, mixed mode, sharing)

说明 JDK 17 装好了!

再输入:

javac -version

应该看到:

javac 17.0.x

验证安装成功
图8:命令行验证 JDK 安装
图片来源:犬小哈教程

到这一步,如果两个命令都能正常显示版本,恭喜你,JDK 17 装好了!

常见问题

Q: 输入 java -version 提示"不是内部或外部命令"?

环境变量没配好。检查一下:

  1. JAVA_HOME 路径对不对
  2. Path 里有没有 %JAVA_HOME%\bin
  3. 配置完要重新打开 cmd 窗口

Q: 安装时提示"找不到指定路径"?

检查一下:

  1. 安装路径里别有中文字符
  2. 路径别太长
  3. 确保目标磁盘有足够空间

Q: 怎么确认 JDK 安装路径?

方法一:

  • 默认路径:C:\Program Files\Java\jdk-17
  • 你安装时如果改过,就用改过的路径

方法二:

  • 打开文件资源管理器
  • 搜索 javac.exe
  • 所在文件夹就是 JDK 安装路径

Q: Path 变量里已经有 Java 相关的路径了怎么办?

可能装过其他版本的 JDK 或 JRE。

  • 如果想用 JDK 17,确保 %JAVA_HOME%\bin 在最前面
  • 或者把旧的 Java 路径删掉

Q: 安装完成后找不到 JDK 安装目录?

检查一下:

  • 默认在 C:\Program Files\Java\jdk-17
  • 可能只装了 JRE,没装 JDK
  • 重新下载安装包(选 Windows x64 Installer)

总结

简单回顾一下:

  1. 下载安装包:用网盘或 Oracle 官网
  2. 运行安装:双击 .exe 按向导来
  3. 配置环境变量:设置 JAVA_HOME 和 Path
  4. 验证:用 java -versionjavac -version 确认

JDK 17 是长期支持版本(LTS),也是 Spring Boot 3.x 要求的最低版本。

如果你想学最新的 Java 开发技术,JDK 17 是个不错的起点。

跟着这篇教程做一遍,你的 Windows 电脑上就有 Java 开发环境了。

接下来就可以开始学 Java 编程了!

有问题随时留言讨论。


参考来源

用我准备的网盘链接(速度更快)

还没上车~ 2021 16 寸 MacBook m1pro 32g 加 1t

带磕碰卖家卖 7k ,不知道贵了还是便宜了?网上搜大部分在 7500-7800 之间,问下兄弟们值得上车吗?不会我再转手这种要按上千的砍价吧

我的头像

之前用国产的大模型写, 感觉其实还行, 就是样式总是多少有点不满意。这两天用上 Gemini 后, 舒服太多了, 基本上只需要告诉他我哪里不满意, 就可以改出更好的让我继续评价。我现在都不敢指定配色、样式了, 感觉丑的地方都来源于我的限制...

话说回来, 小程序叫“半句岛”。没有什么含义, 主要是微信审核太麻烦了, 就只能取一个不成词的名字了。

小程序主打的是信息交换。每个人必须给自己贴上标签,然后可以按需要自主匹配。

例如你想了解其他行业,或者你想入门一个新的爱好,希望找过来人讲一讲。但是为了避免白嫖,所以你也需要贡献自己的行业知识,或者生活经验,来交换信息。

下一步准备增加评价反馈功能,提高对他人有帮助的人的正向反馈。因为个人小程序基本没办法插入盈利的东西,也不需要太多用户,所以不友好的人直接屏蔽掉就好了。如果最后有用户能留下来,即便只是一个几十人的相互交流的社群,也挺好的。





因为测试 nano banana api 接口需要,所以临时让 gemini 写了一个 base64 图片预览工具,仓库如下:

https://github.com/poixeai/base64-image-viewer

粘贴 Base64 图片字符串,或者 Gemini Nano Banana 的完整 JSON 响应体,直接渲染预览图片。

纯 HTML + CSS + JS ,本地双击打开工具页面就可以用了。


顺便感慨一句:AI 时代做这种小工具的成本真的低——“让 AI 写一个”往往比以前去 GitHub / 搜索引擎翻半天更快。

base64-image-viewer

刚刚在看荣耀 Magic OS 10 的更新介绍
有一段是新旧版本的动画效果对比介绍
让我印象深刻
旧版:
旧版动画
新版:
新版动画

相比之下新版会比较符合直觉一些

能明显感受到近两年各家国产手机厂商开始卷系统的动画效果了
但是我记得这个东西苹果在 2017 年就带来了facepalm

如图 :


入户猫位置(红)不好改了 然后各个房间也没任何预留网线 所以有线 mesh 基本不太现实
想改造一下 入户宽带是 500m 的 保证客厅信号和卧室信号 要求不高 能看直播就行 ( 5-10Mb/s )

问题 1:
只用一个路由器在入户猫位置可以覆盖所有卧室吗? 我几年前的 200 块钱的路由器不行 在卧室 1 和 2 信号都很差,因为穿了三堵墙都不止 2026 年买个好的能搞定吗( 500 内)

问题 2:如果一个搞不定,我也无法有线 mesh 的情况下,
我在绿点处搞一个无线 mesh 子路由器可以吗?
我考虑的是 红绿点之间无障碍物,绿点处的子路由器到别的卧室距离也比较近 但是可能穿墙 应该速率还好?

问题 3 这种情况下无线 mesh 体验好吗 我不太追求非常快的速度 我是能达到 5-10Mb/s 就行
在意的是会不会自动切换有延迟,比如从客厅走到卧室,半天切不过来 还要等半天才能达到正常速度

进阶问题 4:
卧室 3 会不会比较尴尬 在卧室 3 基本处于主路由和副路由的信号强度一样的位置 会不会触发频繁切换导致体验不好? 没用过 只是好奇

我并不认为 Obsidian 是一款使用门槛很高的软件。
事实上,只使用 Obsidian 自带的核心功能,就已经可以非常高效地管理我们的笔记与知识。

写这篇文章的目的也很简单:
👉 希望刚接触,或还没有接触 Obsidian 的朋友,可以通过这篇文章快速上手这款软件。

不讲复杂理论,不强推插件,只讲真正「一上手就能用」的部分。


一、安装

Obsidian 是一款跨平台的本地笔记软件,支持 macOS / Windows / Linux / iOS / Android。

官方下载地址:

https://obsidian.md

screenshot-1.0-hero-combo.png

下载安装到本地即可,无需注册账号也能直接使用。


二、仓库(Vault)

在 Obsidian 中,仓库(Vault)本质上就是一个普通文件夹,你的所有笔记都会以 Markdown 文件的形式存放在这里。

如果你使用的是 Mac,非常推荐把仓库位置放在 iCloud 中,方便多设备同步。

PixPin_2026-01-31_19-45-11.png

优点只有一句话:
👉 数据完全属于你,不被任何平台绑定。


三、布局

1. 堆叠标签页

如果你已经看腻了传统浏览器式的标签页布局,可以试试 堆叠标签页,整体视觉会更紧凑,也更有“工作区”的感觉。

1769862805965.png


2. 自由拖动标签

  • 支持通过鼠标自由拖动标签页位置
  • 可以分屏、上下或左右排列

💡 Tips
当你调整好一个顺手的布局后,记得保存下来,后面可以一键恢复(下面的「工作区」插件会讲)。

PixPin_2026-01-31_20-40-24.png


四、笔记

1. 创建笔记

强烈建议你从一开始就 养成添加笔记属性(Frontmatter) 的习惯。

  • 在笔记中输入 ---
  • 然后敲回车
  • Obsidian 会自动生成属性区域
  • 点击最左侧图标可以选择属性类型
    PixPin_2026-01-31_21-55-18.png

这一步会在后期做检索、分类、自动化时非常有价值。


2. 出链与反链

这是 Obsidian 最核心、也是最有价值的能力之一。

  • 输入 [[ 即可创建或引用笔记
  • 跳转到目标笔记后,可以看到哪些笔记引用了它(反链)
  • 即使没有显式加链接,只要提到了笔记名称,也会被识别
  • 当前笔记中还能发现「潜在链接」
    1769869292611.png

一句话总结:
👉 笔记之间会自然“长”成一张知识网络。


3. 命令面板

如果你记不住快捷键或语法,命令面板几乎可以解决 90% 的问题。

  • 左侧栏点击图标打开
  • 或使用快捷键:Command + P
    PixPin_2026-01-31_22-40-33.png

很多功能你根本不需要记,只需要 会搜索


五、语法

1. 链接语法

  • 使用 | 设置别名
    [[我的第二篇笔记|自定义名称]]
  • 使用 # 定位到标题
    [[我的第二篇笔记#标题1]]
  • 使用 ^ 定位到具体段落
    [[我的第二篇笔记^第二篇笔记的一句话]]
    PixPin_2026-02-01_01-29-53.png

2. 嵌入笔记

在链接前加一个 !,即可把内容直接嵌入当前笔记。

  • 嵌入整篇笔记
    ![[我的第二篇笔记]]
  • 嵌入某个标题
    ![[我的第二篇笔记#标题1]]
  • 嵌入某一段内容
    ![[我的第二篇笔记^第二篇笔记的一句话]]
    PixPin_2026-02-01_01-35-51.png

3. 外部链接

标准 Markdown 语法:

[bugshare](https://www.bugshare.cn)

PixPin_2026-02-01_01-39-28.png


4. 其它常用语法

  • 高亮:==高亮内容==
  • 加粗:**加粗**__加粗__
  • 斜体:*斜体*_斜体_
  • 删除线:~~删除线~~
  • 无序列表:-
  • 有序列表:1.
  • 待办事项:- [ ] 任务
  • 引用:>
  • 标注块:
    > [!NOTE]
    > [!SUCCESS]
  • 注释:
    [^1]
    ^[这是注释]
  • 表格:命令面板搜索「插入表格」
    PixPin_2026-02-01_13-16-59.png

六、核心插件(强烈建议启用)

这里必须强调一句:
真的没必要 All in One。
不要把时间浪费在折腾插件上,有需求再装插件,别问我为什么 😖

1. 工作区

用于保存和快速切换布局。

  • 设置 → 核心插件 → 工作区 → 启用
  • 左侧会出现「工作区」图标
  • 给当前布局起个名字即可保存
    PixPin_2026-01-31_21-08-07.png

2. 白板

适合做结构梳理、思维发散。

  • 设置 → 核心插件 → 白板 → 启用
    PixPin_2026-01-31_23-01-57.png

3. 关系图谱

可以非常直观地看到你的知识是如何一步步生长的。

  • 设置 → 核心插件 → 关系图谱 → 启用
  • 打开「生长动画」效果更明显
    PixPin_2026-01-31_23-21-06.png

4. 模板

用于快速创建统一结构的笔记。

  • 设置 → 核心插件 → 模板 → 启用
    PixPin_2026-01-31_23-54-46.png

七、第三方插件(按需)

首次使用需要关闭「安全模式」。

插件推荐网站:

https://obsidian.md/plugins

https://pkmer.cn/products/plugin/pluginMarket

PixPin_2026-02-01_12-47-01.png

推荐插件(只列我觉得真的有用的

  • Iconize:自定义文件夹图标
  • Link Favicons:外部链接显示站点图标
  • Novel Word Count:统计文件夹内笔记数量与字数
  • Number Headings:自动给多级标题编号
  • Excalidraw:在笔记中嵌入手绘图
  • Git:自动提交、拉取、推送笔记版本

八、快捷键

常用快捷键

  • Command + O:快速切换笔记
  • Command + P:命令面板

自定义快捷键

  • 设置 → 快捷键
  • 搜索操作 → 添加快捷键
  • 按下你想要的组合即可
    PixPin_2026-01-31_23-21-55.png

写在最后

如果你是第一次使用 Obsidian,我的建议只有一句话:

先用起来,再慢慢优化。

笔记系统不是一次性设计出来的,而是在长期使用中不断演化的。
Obsidian 的价值,也正是在于它给了你这种「自由生长」的空间。

后续分享 《Obsidian 怎么使用 Claude Code》,欢迎关注。

当前主流 AI 智能体框架有一个共同的局限:智能体只能按预设逻辑执行任务,无法从运行时反馈中持续学习。模型权重是静态的,提示词需要人工迭代,整个系统缺乏自我优化的闭环。

Agent Lightning 针对这一问题提出了解决方案。它是一个框架无关的强化学习包装层,可以套在任意现有智能体外部,让智能体具备在线学习能力。无论底层用的是 LangChain、AutoGen、CrewAI 还是原生 Python 实现,都能以最小改动接入训练流程。

本文将介绍 Agent Lightning 的核心架构和使用方法,并通过一个开源的"自修复 SQL 智能体"项目演示完整的训练流程。

Agent Lightning 的核心特性

Agent Lightning 具备两个关键的设计优势:框架无关性和执行训练解耦。

框架无关性意味着它不绑定特定的智能体实现。无论底层是 LangChain、AutoGen、CrewAI 还是原生 Python 代码,都可以通过统一的接口接入训练流程,无需重构现有逻辑。

执行与训练解耦则是指智能体的推理执行和强化学习训练在架构上分离。智能体正常处理业务请求,训练模块在后台异步收集反馈、更新策略。这种设计保证了生产环境的稳定性,同时支持持续优化。

Agent Lightning 的工作原理

Agent Lightning 由四个核心组件构成:

Runner 负责智能体的沙箱执行。它为智能体提供隔离的运行环境,执行任务并记录完整的行为轨迹,包括输入、输出、中间状态和最终结果。Trainer 负责策略优化。它根据 Runner 收集的轨迹数据计算奖励信号,通过强化学习算法更新智能体的行为策略。LightningStore 是持久化存储层,保存所有历史轨迹、奖励记录和模型检查点,支持离线分析和增量训练。

VERL(Volcano Engine Reinforcement Learning)专门处理多步骤任务中的信用分配问题。在长序列决策中,最终奖励需要回溯分配到各个中间步骤。VERL 通过时序差分等方法,将整体奖励拆解到具体动作,解决稀疏奖励场景下的训练难题。

构建一个自纠正智能体

理论讲完了。下面看怎么落地。目标是构建一个学会简洁回答的智能体。

先装库,它会包在现有 LLM 调用外面。

 pip install agentlightning

普通智能体就是发提示、拿回复。用 Agent Lightning 的话,要在函数外面加一个

@agl.rollout

装饰器。意思是告诉系统:盯着这个函数,给它打分,帮我改进它。

下面这个例子是一个回答首都城市的简单智能体。目标是让它输出精确答案(比如直接回"Paris")而不是废话连篇("The capital is Paris")。

 import agentlightning as agl  
from openai import OpenAI  

# 1. Define the Reward (The Coach's Whistle)  
def exact_match_reward(prediction, target):  
    # Reward is 1.0 if correct and concise, 0.0 otherwise  
    return 1.0 if prediction.strip().lower() == target.strip().lower() else 0.0  

# 2. Define the Agent  
@agl.rollout  
def capital_city_agent(task, prompt_template):  
    # Use the dynamic prompt template provided by the Trainer  
    system_prompt = prompt_template.format(**task)  
      
    response = client.chat.completions.create(  
        model="gpt-4o",  
        messages=[  
            {"role": "system", "content": system_prompt},  
            {"role": "user", "content": f"Capital of {task['input']}?"}  
        ]  
    )  
      
    prediction = response.choices[0].message.content  
     return exact_match_reward(prediction, task['target'])

这样就不用手动改提示词了,交给 Trainer。

 # Initialize the optimizer (Automatic Prompt Optimization)  
optimizer = agl.APO(inference_client=client)  

# Define a starting "bad" prompt  
initial_prompt = agl.PromptTemplate("You are a geography helper.")  

# Start the gym session  
trainer = agl.Trainer(  
    algorithm=optimizer,  
    initial_resources={"prompt_template": initial_prompt}  
)  

trainer.fit(  
    agent=capital_city_agent,  
    train_dataset=[{"input": "France", "target": "Paris"}, ...],  
 )

跑完之后,Agent Lightning 会自动把提示词改写成类似这样:"You are a precise geography assistant. Output ONLY the city name with no punctuation."

总结

Agent Lightning 为现有智能体提供了一套轻量级的在线学习方案,通过框架无关的设计和执行训练解耦架构,降低了强化学习在智能体开发中的接入门槛。

落地过程中需要注意几个问题:奖励函数设计直接影响优化方向,指标定义不当会导致智能体学到错误行为;训练过程消耗计算资源,多智能体场景需要做好监控;持续学习带来的模型漂移也需要治理机制保障,防止智能体偏离预期的安全边界。

从更大的视角看,Agent Lightning 代表了智能体开发从静态部署向动态进化的转变。随着这类工具的成熟,智能体将逐步具备自适应能力,成为真正意义上的学习型系统。

https://avoid.overfit.cn/post/b190f67bd0914e9fa18657513f29271f

作者:Aarav Sharma

引言

在大语言模型(LLM)的应用中,合理配置参数是获得理想输出效果的关键。本文将详细解析三个最重要的参数:temperature、top_p和max_tokens,介绍它们的含义、调优技巧,并通过实际应用案例展示参数实验对比。

参数详解

Temperature(温度)

含义

Temperature参数控制生成文本的随机性和创造性。数值范围通常在0到2之间:

  • 低值(接近0):模型更加确定性,倾向于选择概率最高的词,输出更可预测、更保守
  • 高值(接近2):模型更具随机性,会考虑更多可能性,输出更富创造性但也可能不连贯

调优技巧

  • 创意写作:使用较高值(0.7-1.0)以增加多样性
  • 问答系统:使用较低值(0.2-0.5)以确保准确性
  • 代码生成:使用极低值(0.1-0.3)以保持逻辑一致性
  • 默认推荐:0.7 是平衡创造性和准确性的良好起点

Top-P(核采样)

含义

Top-P参数控制模型从累积概率达到P值的最小词汇集合中进行采样。例如:

  • top_p = 0.9:模型从累计概率达到90%的词汇中进行选择
  • top_p = 0.1:模型仅从最有可能的前10%词汇中选择

这种方法动态地调整候选词汇数量,相比固定数量的选择更灵活。

调优技巧

  • 高值(0.8-0.95):保留更多可能性,适合开放性生成
  • 低值(0.1-0.5):限制选择范围,提高输出的一致性
  • 默认推荐:0.9 是常用的平衡值

Max Tokens(最大令牌数)

含义

Max Tokens参数设置模型单次生成的最大token数量。Token可以是单词、子词或字符,具体取决于模型的分词器。

调优技巧

  • 短回答:设置较小值(50-200)以节省资源
  • 长文档:设置较大值(500-2048)允许详细输出
  • 默认推荐:根据具体应用场景调整,默认值2048适用于大多数情况

实际应用建议

在本项目中的最佳实践

  1. 对话模式:使用默认配置(temperature=0.7, top_p=0.9, max_tokens=2048)
  2. 创意模式:适当提高temperature至1.0以上,top_p至0.95
  3. 精确模式:降低temperature至0.3以下,top_p至0.5以下

参数调节策略

  • 逐步调整:每次只改变一个参数,观察效果变化
  • 场景化配置:为不同应用场景保存不同的参数组合
  • 性能监控:注意高参数值可能导致更长的生成时间和更高的计算成本

结论

合理配置LLM参数对于获得理想的生成效果至关重要。Temperature、top_p和max_tokens这三个参数各有其作用:

  • Temperature控制创造性程度
  • Top-P管理词汇选择的多样性
  • Max Tokens限制输出长度

在实际应用中,我们需要根据具体任务需求来平衡创造性、准确性和性能。通过本项目的实验可以看出,中等参数配置(temperature=0.7, top_p=0.9)在多数场景下都能提供良好的输出质量,这正是我们在项目中采用的默认配置。

通过不断实验和调整,我们可以找到最适合特定应用场景的参数组合,从而最大化LLM的实用价值。

核心摘要 (TL;DR)

  • 工具:Ollama (最流行的本地大模型运行工具)。
  • 目标:在本地电脑运行大模型,并提供 API 给 Python 调用。
  • 痛点解决:教咱们如何用国内 ModelScope 替代 HuggingFace 实现极速下载。
  • 干货:包含修改端口、显存计算公式、以及 Embedding/多模态等概念科普。

01. Ollama 介绍

官网地址:https://ollama.com/

Ollama 是目前最火的本地大模型部署工具。
简单来说,它能帮咱们快速拉取模型文件,让模型在本地直接运行并进行对话。同时,它还能把模型打包成一个标准的接口,通过端口开放给咱们写的 Python 脚本调用。

对于咱们来说,它就是在大模型时代装在电脑里的“运行环境”,必不可少。

02. 安装 Ollama

  1. 下载:登录官网 https://ollama.com/
    ollama_site
  2. 选择版本:点击 Download 按钮,根据咱们的操作系统(Windows/Mac/Linux)下载。
    download_ollama_via_platform
  3. 安装:打开下载好的安装包,选一个咱们喜欢的位置安装即可。
  4. 验证:安装完毕后,开始菜单里会出现一个羊驼图标。
    ollama_icon
  5. 测试运行:按下 Win+R 打开运行窗口,输入 cmd 打开命令提示符。输入命令 ollama --version。如果看到版本号,就说明 Ollama 已经安装完毕,正在运行了。
    run_cmd_command
    check_ollama_version
    第一阶段顺利完成!

03. Ollama 常用命令速查

这些命令咱们以后会经常用到,建议收藏:

场景命令示例备注
第一次下模型ollama run qwen3:7b会自动先 pull 再运行,一步到位
只下载不运行ollama pull llama3:8b适合提前囤模型
国内加速ollama pull modelscope.cn/Qwen/Qwen3-7B-GGUF推荐!下文会细讲
查看本地库存ollama listollama ls大小/ID/修改时间一目了然
删除省空间ollama rm llama2:latest支持通配符,可写 llama2:*
给模型改短名ollama cp qwen3:7b q7后面直接 ollama run q7 方便调用
查模型详情ollama show q7参数量、量化层、标签全列出

04. 下载模型(解决网速慢的问题)

Ollama 官网收录了很多模型,可以通过详情页复制命令下载,但由于服务器在海外,咱们在国内访问经常断连,速度也很慢。

主流的模型平台是 HuggingFace,但它也在海外,国内下载需要魔法工具。
咱们的解决方案:使用阿里的 魔搭社区 (ModelScope)

操作步骤:

  1. 进入 HuggingFace 点击 Models,或者进入魔搭点击模型库。
  2. 在搜索框输入咱们想要的模型,比如 Qwen3-0.6B-GGUF

    注意:Ollama 目前主要支持 GGUF 格式,搜索时一定要带上这个后缀。
    hugging_face_search_gguf
  3. 进入模型详情页,复制模型 ID,例如 Qwen/Qwen3-0.6B-GGUF
    click_to_copy_model_address
  4. 回到命令提示符,加上前缀进行下载,网速直接拉满:

    • 魔搭下载 (推荐): ollama pull modelscope.cn/Qwen/Qwen3-0.6B-GGUF
    • HuggingFace 下载: ollama pull hf.co/Qwen/Qwen3-0.6B-GGUF
  5. 下载完毕后,运行 ollama list 查看信息:
NAME                                        ID              SIZE      MODIFIED
modelscope.cn/Qwen/Qwen3-0.6B-GGUF:latest   xxxxxxx         xxx MB    x ago

05. 运行模型

在命令行工具输入 ollama run modelscope.cn/Qwen/Qwen3-0.6B-GGUF
看到交互界面后,咱们就可以愉快地跟大模型对话了。
ollama_run_result

06. 更改服务端口(进阶)

Ollama 默认服务运行在端口 11434 上。如果咱们在自己的服务器上部署,为了安全或避免端口冲突,可以修改它。

Windows 环境

  1. 退出 Ollama:在任务栏右下角的托盘图标上右键,选择 Quit Ollama
    quit_ollama
  2. 设置环境变量

    • 按下 Win + S,搜索“编辑账户环境变量”并打开。
    • 在“用户变量”部分,点击“新建”。
    • 变量名OLLAMA_HOST
    • 变量值0.0.0.0:5656 (假设咱们想改到 5656 端口,0.0.0.0 表示允许所有网卡访问)。
      add_OLLAMA_HOST_to_env_vairable
  3. 重新启动:从开始菜单重新运行 Ollama 软件。
  4. 检验:在浏览器输入 http://localhost:5656,如果显示 Ollama is running 说明端口修改成功了。

Linux 环境

  1. 执行命令:sudo systemctl edit ollama.service
  2. 在打开的编辑器中(通常是空白或带注释),加入以下内容:
[Service]
Environment="OLLAMA_HOST=0.0.0.0:5656"
  1. 保存并退出,然后重载并重启服务:
sudo systemctl daemon-reload
sudo systemctl restart ollama

07. 在 Python 脚本中使用模型

为了运行连接 Ollama 的 Python 脚本,我们需要准备以下环境:

  • Python 版本:Python 3.8 以上
  • OpenAI 库依赖:在命令行输入 pip install openai

Ollama 完美兼容 OpenAI 的 API 格式,所以咱们直接用 OpenAI 的库就行:

from openai import OpenAI

# 初始化客户端
client = OpenAI(
    # 这里的端口号要对应咱们上面修改后的端口号,记得加上 /v1
    base_url='http://localhost:5656/v1',
    # Ollama 不需要真正的 Key,但这里随便填一个,不能留空
    api_key='ollama',
)

# 发起对话请求
response = client.chat.completions.create(
    # 填入咱们在 ollama list 中看到的模型名称
    model="modelscope.cn/unsloth/Qwen3-0.6B-GGUF",
    messages=[
        {"role": "system", "content": "你是一个有用的助手。"},
        {"role": "user", "content": "你好,请简单介绍一下你自己。"},
    ]
)

print(response.choices[0].message.content)

08. 常见问题 (Q&A)

这里整理了咱们在入门时最关心的问题:

Q: 除了 Ollama 还有哪些方式可以部署,它们有什么差别?
A:

  • LM Studio / AnythingLLM:带有图形界面的部署工具。适合完全不懂代码或者完全不想碰代码的初学者,也可以一键建立知识库做 RAG。
  • vLLM:高性能推理框架。通常用于服务器级别,速度极快,适合多人并发,工业级部署使用。
  • 差别:Ollama 更轻量,适合开发;LM Studio 胜在可视化;vLLM 胜在极致性能。

Q: Ollama 开机自动启动,我要怎么关闭?关闭后如何手动启动?
A:

  • Windows:右键点击任务栏图标 -> Quit Ollama 只是临时关闭。要彻底关闭自启,请在 任务管理器 -> 启动应用 中找到 Ollama 并设为禁用。
  • Linux:使用命令 sudo systemctl disable ollama 关闭自启。
  • 手动启动:Windows 直接运行桌面图标;Linux 执行 ollama serve 即可。

Q: HuggingFace 和魔搭 (ModelScope) 有什么区别?
A:

  • Hugging Face (HF):全球最大的“AI 模型图书馆”,资源最全、社区最活跃,但服务器在海外,国内访问速度较慢。
  • 魔搭 (ModelScope):阿里旗下的国内版“模型图书馆”。国内下载速度极快,模型齐全(基本和 HF 同步),主要是为了解决国内下载慢、需要魔法的问题。

Q: 平台看起来很丰富,还有什么别的好玩儿的功能?
A:

  • Spaces / 创空间:可以直接在 Web 上体验最新的模型应用(如 AI 绘画、变声),不用本地部署,但有时需要排队。
  • Datasets (数据集):训练模型的数据集也可以在上面下载。

Q: 大模型有什么类型?
A:

  • 语言模型 (LLM):常规的大模型,如 Llama3, DeepSeek, 千问。主要是聊天和文字处理。
  • 多模态模型:如 LLaVA。能看图片,根据图片进行对话,也就是传统的大模型 + 能看图的眼睛。
  • 嵌入模型 (Embedding):用来将文字直接转化为向量数值。主要用在 RAG (检索增强生成) 中,对问题进行搜索以找到相近的文档回答。
  • 视觉/视频/语音模型:用以生成图像、视频和语音。

Q: 我该如何快速计算我的电脑能支持多大的模型?
A: 一般来说模型的占用可以通过一个快速公式来计算:
模型显存占用 ≈ 参数量 × 0.7

  • 比如下载 0.6B 模型,全量参数 (16bit) 就是:0.6 × 0.7 ≈ 0.42GB
  • 如果是 7B 模型(4-bit 量化):7 × 0.7 ≈ 4.9GB,咱们至少需要 6GB 显存。

Q: 大模型不是需要显卡吗?为什么 Ollama 可以运行在没有显卡的设备上?
A: Ollama 底层使用了 llama.cpp 技术。如果它检测到咱们没有显卡,会将模型权重从显存(VRAM)加载到 系统内存 (RAM) 中,使用 CPU 指令集进行计算。虽然速度比在显卡上慢,但让手机、普通轻薄本等设备也有了运行大模型的可能性。


本文作者: Algieba
本文链接: https://blog.algieba12.cn/run-our-own-model-on-pc/
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

这里先做一下简单的科普:

OpenClaw 的名字经历了三次变更,第一次叫做 ClawdBot,后来因为名字跟 Claude 太过相似,被 CLaude 告侵权,遂改名 MoltBot

但是后来在改名过程中遭遇域名和社交账号被抢注,甚至出坑同名加密货币割韭菜的情况,导致名称传播受阻。

最终定名为:OpenClaw

所以,名字经历先后顺序为:ClawdBot -> MoltBot -> OpenClaw

大家不要因为名字困惑了,怀疑是不是自己下错软件了,他们都是同一个。

一、什么是 OpenClaw?

OpenClaw(曾用名 Clawdbot)是一款 2026 年爆火的开源个人 AI 助手,GitHub 星标已超过 10 万颗。与传统 AI 聊天机器人的根本区别在于:

  • 真正的执行能力:不仅能回答问题,还能实际操作你的电脑
  • 24/7 全天候待命:在你睡觉时也能主动完成任务
  • 完全开源免费:数据完全掌控在自己手中
  • 支持多种通讯平台:在国外,WhatsApp、Telegram、Discord、Slack、iMessage 等,在国内,飞书,钉钉等各大厂商的即时聊天软件已经支持接入

它能做什么?

它不只是回答问题的聊天机器人,而是真的能在你电脑上动手操作。比如你告诉它“帮我整理一下上个月的邮件”,它就默默去处理了;你睡觉时,它还能继续干活,退订广告、预约行程、甚至找找 Bug。

它完全免费,你的数据都在自己手里。而且可以用钉钉,飞书,WhatsApp、Telegram等各类即时通讯软件来指挥他干活!

简单来说,一句话交给它,从整理桌面文件到控制家里灯光,它都默默帮你搞定。是你电脑里真正的贾维斯!超级智能的AI助理!

二、安装nodejs

后面执行一键安装命令,可以自动安装nodejs,但是如果为了加快速度,防止安装意外,可以先安装nodejs:

官方下载地址:https://nodejs.org/zh-cn/download

三、开始安装

一)设置 PowerShell 执行权限

以管理员身份运行 PowerShell:

  1. Win 键,搜索 PowerShell
  2. 右键点击 Windows PowerShell
  3. 选择 以管理员身份运行
  4. 点击 确认

在管理员 PowerShell 窗口中,依次执行以下两条命令:

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

这是什么意思?

  • 第一条命令:允许当前用户运行本地和下载的脚本
  • 第二条命令:允许当前用户运行本地和下载的脚本
⚠️ 安全提示:这些命令只会影响您自己的账户,不会影响系统安全或其他用户。

二)执行一键安装命令

复制以下命令,粘贴到 PowerShell 窗口中,按 Enter 执行:

iwr -useb https://openclaw.ai/install.ps1 | iex

安装过程会自动完成:

  • 检测系统环境
  • 安装必要依赖(Node.js 等)
  • 下载 OpenClaw 核心文件
  • 配置环境变量
  • 启动配置向导
注意:如果命令执行后,还是报错,可以自己到官网下载node安装包,自己安装node环境,注意版本最好在 node v22.x 以上,node官网下载地址:https://nodejs.org/zh-cn/download,若还是不懂怎么安装,点头像进我主页找到我,拉你进交流群

四、初始配置向导

安装完成后,会自动进入配置向导(openclaw onboard)。

一)风险告知

这一步主要是告诉你,使用OpenClaw可能会有一些风险。请问你是否继续?
按 向左方向键 ←,选择 Yes,按 Enter 回车确认

二)选择 QiuickStart 模式

三)配置 AI 模型 API Key

OpenClaw 需要连接到大语言模型才能工作。Openclaw 比较费token,国外模型成本高,门槛也高,这里我选择国内的智谱的 GLM 4.7

如果没有智谱的API Key,点击官方地址自己注册账号获取API key:https://www.bigmodel.cn/glm-coding?ic=RBSKXMPNJP

输入自己的 API Key:

四)选择 AI 模型

这里我选择默认的GLM 4.7,也是智普当前的旗舰模型

五)连接即时通讯平台

配置完 AI 模型后,OpenClaw 会询问你要连接哪个通讯平台?

OpenClaw 原生支持的即时通信平台主要是海外的 WhatsApp、Telegram、Discord、Slack、iMessage 等,国内用户不习惯,这里国产即时通信软件大厂也跟进了,现在钉钉,飞书等都已支持接入OpenClaw

后面会带领大家把飞书机器人接入 OpenClaw,使大家可以通过飞书即可指挥OpenClaw为我们干活,但是飞书配置比较复杂,这里我们先选择跳过,后面我们可以通过继续进行配置:

六)选择Skills

这里也选择:No,暂不配置,后面通过UI界面进行配置:

七)是否开启Hooks

操作步骤:先敲空格,表示选中当前项,再敲回车键

八)启动服务并打开UI界面

此时它会自动再打开一个命令窗口来启动服务:

这个过程是在启动服务,可能会需要等一点时间

同时,大约过30秒左右,我们回到刚才的设置窗口,选择 Open the Web UI ,打开 OpenClaw 的UI界面:

浏览器自动打开Web UI界面:

九)测试一下

五、接入飞书机器人

我们需要先到飞书平台创建自己的机器人来接入OpenClaw:

一)来到飞书开发者后台

飞书开放平台地址:https://open.feishu.cn

没有飞书账号的,需要自己注册账号

点击右上角进入 开发者后台

二)创建应用

三)填写应用信息

四)获取自己的应用凭证

五)给应用添加机器人

六)给应用配置权限

把即时通讯相关的权限全部开通:

七)创建版本并发布

来到飞书客户端进行审批:

八)安装飞书插件

打开powershell,输入以下命令,安装飞书插件:

openclaw plugins install @m1heng-clawd/feishu

安装成功后,再打开一个新的命令窗口,开始配置飞书插件:

输入命令:openclaw config

选择渠道:

选择配置链接:

输入飞书的AppID,AppSecrect:

域名选择中国的:

接受群组聊天:

选择完成:

选择yes:

选择open:

选择继续,完成配置:

重启服务,使配置生效:
控制可以看到飞书插件已经配置成功

七)回到飞书后台设置事件回调

选择 使用长连接接收事件

可以看到添加事件按钮由原来的灰色不可点击变为可点击:

添加接收消息事件:

给应用开通获取通讯录基本信息的权限:

重新发布版本:

跟前面的步骤一样,发布为在线应用即可。

现在可以在 飞书中与 AI 助手对话了!

八)在飞书中与OpenClaw对话

来到飞书客户端或者手机飞书app上:

以下是openclaw文件夹下面的文档内的内容:

现在我跟废水机器人对话,让他告诉我指定文档内是什么内容:


六、访问 Web 控制面板

配置完成后,PowerShell 窗口底部会显示控制面板链接,格式类似:

Control UI: http://127.0.0.1:18789
  1. 复制完整链接
  2. 在浏览器中打开
  3. 即可看到可视化UI管理界面

七、常用命令速查

命令功能
openclaw onboard重新进入配置向导
openclaw status查看运行状态
openclaw health健康检查
openclaw gateway start启动服务
openclaw gateway stop停止服务
openclaw update更新到最新版本
openclaw doctor诊断问题
openclaw uninstall卸载 OpenClaw

八、常见问题解答

Q1: 安装飞书插件提示:spawn npm ENOENT

问题原因:这可能是openclaw的一个bug,可以等官方更新,也可以自己去官方仓库提issue

解决步骤:

定位问题代码

文件路径:

C:\Users\Administrator\AppData\Roaming\fnm\node-versions\v22.14.0\installation\node_modules\openclaw\dist\process\exec.js

修改代码

找到 runCommandWithTimeout 函数中的 spawn 调用,修改如下:

修改前:

const stdio = resolveCommandStdio({ hasInput, preferInherit: true });
const child = spawn(argv[0], argv.slice(1), {
    stdio,
    cwd,
    env: resolvedEnv,
    windowsVerbatimArguments,
});

修改后:

const stdio = resolveCommandStdio({ hasInput, preferInherit: true });
// On Windows, npm must be spawned with shell: true or use .cmd extension
let command = argv[0];
let useShell = false;
if (process.platform === "win32" && path.basename(command) === "npm") {
    useShell = true;
}
const child = spawn(command, argv.slice(1), {
    stdio,
    cwd,
    env: resolvedEnv,
    shell: useShell,
});

Q2: 提示 "openclaw 命令找不到"

解决方法:

  1. 关闭所有 PowerShell 窗口
  2. 重新打开 PowerShell
  3. 如果还不行,执行 exec bash 或重启电脑

Q3: 安装卡住不动

解决方法:

  1. Ctrl + C 中断当前操作
  2. 执行:openclaw doctor 检查问题
  3. 如提示网络问题,检查防火墙设置

Q4: API Key 配置错误

解决方法:

  1. 执行:openclaw onboard
  2. 选择重新配置 API Key
  3. 确保密钥格式正确

Q5: 端口 18789 被占用

解决方法:

openclaw gateway --port 18790

使用其他端口启动服务。

九、成本说明

OpenClaw 软件本身完全免费,主要成本来自 AI 模型 API 调用,可选择国产大模型,降低成本。


结语

OpenClaw 代表了个人 AI 助理的未来趋势——从"聊天工具"进化为"执行工具"。虽然目前的配置过程对小白用户有一定门槛,但一旦完成设置,您将拥有一个 24/7 待命的超级助手。

vibe coding 了一个分析工具,来分析 HodlAI 项目的可持续性。

建的模型很简单:用户持币 1000 美元,先扣掉 3%,也就是 30 美元的交易税。然后就可以每天享有 API 额度,目前来看,持有 1000 美元,每天就可以享有最高 100 美元 API 额度。

从这些数值看起来,就感觉非常不可持续。但我还是做了一个分析工具,按照「每天有 1000 美元的新增资金去购买代币」这样简单的线性模型来揭示,这样的 Holding 权益,有多不靠谱。


先看一下按照现在每天 10%(对应年化 3600%)的持有收益,模拟 30 天,亏损 45000 美元。即使 Builder 把用户买币的钱全部用掉,也无法弥补亏损。
![]( )

然后是把每天的收益率降低到 2%(年化 700%),模拟 30 天( 1 个月),亏损 8400 美元。但 Builder 可以把用户买币收到的钱用掉 30%,来弥补亏损。
![]( )

但是如果每天收益率仍然保持 2%(年化 700%),模拟天数延长到 120 天( 4 个月),亏损 140000 美元。即使 Builder 把用户买币的钱全部用掉,也无法弥补亏损。
![]( )

每天收益率进一步降低到 0.5%(年化 180%),模拟天数 120 天( 4 个月),亏损 32000 美元。但 Builder 可以把用户买币收到的钱用掉 30%,来弥补亏损。
![]( )

每天收益率进一步降低到 0.5%(年化 180%),模拟天数延长到 420 天( 1 年零 3 个月),亏损 430000 美元,即使 Builder 把用户买币的钱全部用掉,也无法弥补亏损。
![]( )

那么收益率降低到合理水平呢?如每天 0.03%(年化 10%),模拟 720 天( 2 年),亏损 56000 美元。但 Builder 可以把用户买币收到的钱用掉 8%,来弥补亏损。
![]( )

再合理一些,每天 0.01%(年化 3%),模拟 720 天( 2 年),亏损 4000 美元。但 Builder 可以把用户买币收到的钱用掉 1%,来弥补亏损。
![]( )



上面之所以把 Builder 卖币作为一个选项,是因为币价在涨的过程中,Builder 持有的币也是在不断增值(盈利)的,确实可以通过卖币,来给这个不可持续的模式输血。但卖币也是有限度的,假设用户总共买了 10000 美元的币,那么如果 Builder 卖出高于 10000 美元的币,会把币价压低到涨价前的价格,这时 Builder 通过币价上涨产生的增值也会清零,无法再继续卖币来补贴亏损。(这个需要熟悉 AMM 的机制,对家买 10000 美元,币价上涨,你再卖 10000 美元,币价就会回去)。

从上面的图形,可以明显看到以下几点:
1 是,现在的每天 10%回报率太夸张了,明显不可持续。
2 是,时间越拉长,这种模式越不可持续,甚至靠 Builder 卖币也不能维持。
3 是,想要持续下去,只有降低回报率,到一个非常低的水平(持有 1000 美元,每天可用 0.1 美元 API )。


前期( 1 周内)看不出问题很正常,亏损金额还很小,甚至还可以补贴。但看看上面的图形,能坚持 1 个月或几个月就非常不错了。

后期只有 2 条路:
1 是,快速降低 API 可用额度,到一个让人无法察觉的程度(持有 1000 美元,每天可用 0.1 美元 API ,年化 3%),跟存款利息没多大差别;
2 是,趁币价高,把流动性池清空,卷款跑路;


分析这个不是打击谁的热情,而是我深深怀疑这个模式的合理性,有人能解答我的疑问吗?

现在做需求已经不是先想代码怎么写,而是先想怎么 prompt 了

预估工时也不再是代码编写的时间,而是 Agent 多久能跑完,代码的生产速度≈Token 的生成速度

gpt-5.2 真是一个靠谱的伙伴,基本上每次 prompt 都能拿到预期的结果


BTW, codex-viz 是我 vibe coding 的一个统计 codex 本地用量的工具,有需要的可以自取
https://github.com/onewesong/codex-viz

img

这个是一个 VsCode 插件,使用上很友好,原理是使用 Claude 里面的便宜模型 Haiku 或者 Gemini 3 Flash 阅读,然后使用高参数模型(比如:Claude Sonnet 4.5 和 Gemini 3 Pro) 写代码:

实测,可以比 Claude 省钱 95%,编码效果完全一样

使用方式:

1 ,下载 VS Code (如果没有你就去百度一下)


2 ,安装

搜索:Claude Code Cheaper

3 ,使用


里面有赠送额度!实测折合比直接使用 Claude Code 便宜 95% !