普通视图

发现新文章,点击刷新页面。
昨天以前Kitten 的时间胶囊

端侧 LLM 大模型推理

作者 KittenYang
2024年6月13日 15:07

背景

端侧 LLM 大模型推理

底层 LLM 的军备竞赛正在如火如荼地进行着,上层的产品能力似乎也还没得到释放,做来做去就是聊天工具、RAG问答,但似乎这里还有一块基础能力亟待填补 —— LLM on device(端侧大模型)。

安卓 OS 不断渗透到电视、车机、广告屏,本质上还是我们需要特定场景下的智能设备;或者是把一部分专门的能力剥离成一个独立的设备,诸如树莓派、机顶盒、蓝光播放器、声卡。这些设备形态的底层逻辑是:

  1. 具有独立的使用场景

  2. 支持运行程序

而大模型其实就是一种特殊的 OS,因此自然而然地就可以联想到,未来会有越来越多的大模型被移植到我们身边随处可见的智能设备上,小到一个闸机,大到航天军工,LLM on Device 一定是必然趋势。但不是说所有场景全部会变成本地,而是端云协同,端上解决必要的、轻量的任务,云端解决复杂的、耗时的任务。云+端,会是未来 AI 的必然方向,正如那句成年人不做选择,我全都要。

意义

端侧大模型的意义主要体现在以下几个方面:

  1. 提高用户体验:通过在手机等设备上直接运行端侧大模型,可以实现更快速、更准确的用户需求理解和服务,提升用户体验

  2. 保护隐私信息:端侧大模型能够在不上传个人数据到云端的情况下使用,从而在保护隐私信息方面具有优势

  3. 降低算力成本:端侧大模型有助于解决算力成本问题,通过优化计算资源的使用,实现任务负载分配和降本增效

  4. 支持规模化应用:端侧AI支撑规模化扩张,有助于人工智能在用户软件使用方式上带来根本性变革

  5. 推动 AI 技术渗透到社会每个角落:随着端侧大模型不断下放到各种设备,平时车站咨询台的工作人员全部可以换成 AI 机器人;类似的还有导游、咨询师、门诊问诊等职业(但我觉得在中国很难大面积普及,因为这可能不利于就业)

实战

语言

既然要跨平台移植,那必须首选 C++ 这位老选手了。有句话叫流水的高级语言,铁打的 C++。纵观涉及到底层能力或是多平台移植的需求,都能看到 C++ 的身影。因此业界最流行的一些通用能力库,都有对应的 C++ 版本。

开源方案对比

mlx:可以理解为 NumPy 的 C++ 版本,都是用来处理数值计算(多维数组)和科学计算(线性代数运算),所以凡是涉及到处理大量数据的工作都适用,不仅局限于机器学习领域(还包括比如数据科学)。只不过 NumPy 是 python,MLX 用 C++  实现,并且对 Apple 平台的芯片做了优化,可以充分释放 Apple 芯片的潜力。这么一来,就可以用来把模型移植到 Apple 平台,因为模型的推理本质上还是在做数组运算。另外,mlx 还提供了 C 语言接口和 Swift 接口

llama.cpp:则是用 C++ 从头到尾撸了一个 Transformer 推理框架,依赖极少,支持 CPU 推理,当然也支持各种底层库推理(CUDA/OpenCL),具有 FP16 和 FP32 的混合精度、支持8/4bit量化等等。

mlc-llm:  和 llama.cpp 类似的跨平台推理框架,号称性能远超 llama.cpp,

当然其实还有好几个类似的框架,比如 tgilightllmvllmexllamav2(only server)、FasterTransformer、FlashAttention 等等,各有优缺点,就不一一举例了。按社区的热度、生态、性能、功能来看目前 llama.cpp 绝对是遥遥领先(颇有种17年torch、keras、caffe、mxnet、tensorflow...群雄逐鹿的阵势),本文主要讨论 mlx、llama.cpp、mlc-llm,主要评测三款推理框架在 Mac、iPhone 设备上的性能。

Mac: Apple M1,16G, macOS13.5

iPhone: A16, 6G(iPhone14 Pro\iPhone 15)

端侧 LLM 大模型推理

评分标准:优秀 5 —— 0 差

端侧 LLM 大模型推理

mlc-llm: 性能最强;文档优秀;兼容设备最广;但社区不怎么活跃,bug 多,模型转化繁琐;

llama-cpp: 社区最活跃;性能一般;支持模型多;部署简单

mlx: 性能一般;苹果生态友好;无法兼容其他生态;

llama.cpp

把 LLM 跑在 macOS, Linux, and Windows,用 C++ 实现。目前使用范围最广的端侧大模型部署方案,是许多项目源头。

架构特点

  1. llama.cpp 无需任何额外依赖,可以直接编译出可执行文件,这使得它相比 Python 代码对 PyTorch 等库的要求更为简便

  2. 它支持将模型参数从32位浮点数转换为16位甚至8、4位整数,以实现模型的量化

  3. llama.cpp 支持 CPU 推理,并且也支持各种底层库推理(如CUDA/OpenCL),这表明它具有良好的兼容性和灵活性

  4. 由于没有依赖其他深度学习框架结构,llama.cpp 需要自己从头建图,完成数据流转、串联算子、调度运算等一系列基础工作,同时还要兼顾速度性能。相当于实现了一

  5. llama.cpp 还提供了服务化组件,可以用于构建HTTP API服务和与之交互的简单web前端

mlc-llm

和 llama.cpp 同属底层推理框架,可以把 LLM 直接跑在 laptops/servers(Nvidia/AMD/Apple), iPhone, Android, and Chrome browser 上。比 llama.cpp 适配更多平台,且性能也好于 llama.cpp。

mlc 有专门的权重格式,你需要做一些额外的操作才能把目前公开的 LLM 移植到上面。当然它同样也提供了预编译好的模型。

两个关键原料

要在 mlc-llm 下面跑起来,你需要两部分原料。如果是主流的模型,官方提供了现成的,如下:

  1. 模型权重转换为 MLC 格式(例如 RedPajama-INCITE-Chat-3B-v1-q4f16_1-MLC

端侧 LLM 大模型推理

如何把通用的 .safetensors 模型转成上面的 mlc 格式呢?官方也提供了脚本和文档 https://llm.mlc.ai/docs/compilation/convert_weights.html(u1s1,mlc-llm 的文档还是非常完整的)

mlc_chat convert_weight ./dist/models/phi-2/ \
    --quantization q4f16_1 \
    -o dist/phi-2-q4f16_1-MLC
  1. 包含推理逻辑的模型库(请参阅 repo binary-mlc-llm-libs

端侧 LLM 大模型推理

一个模型库包含的东西如下:

  1. 模型架构(例如,mistral、phi-msft)

  2. 量化方案(例如 q3f16_1、q0f32)

  3. 影响内存规划的元数据(例如 context_window_size、sliding_window_size、prefill_chunk_size)

  4. 平台(例如 cuda、webgpu、iphone、android)

如果是自己的模型,如何编译上面的二进制文件呢?需要手动操作:https://llm.mlc.ai/docs/compilation/compile_models.html

mlc_chat compile ./dist/phi-2-q4f16_1-MLC/mlc-chat-config.json \
    --device iphone -o dist/libs/phi-2-q4f16_1-iphone.tar

组装成静态库

文档:https://llm.mlc.ai/docs/deploy/ios.html#id3

出了准备上面两部分原料,还需要一个轻量的运行时和 tokenizer,把上面两个原料打成一个静态库

最后打出来的产物如下:

>>> ls ./build/lib/
libmlc_llm.a         # A lightweight interface to interact with LLM, tokenizer, and TVM Unity runtime
libmodel_iphone.a    # The compiled model lib
libsentencepiece.a   # SentencePiece tokenizer
libtokenizers_cpp.a  # Huggingface tokenizer
libtvm_runtime.a     # TVM Unity runtime

权重拷贝到App

./prepare_params.sh

Xcode 编译 App

修改证书,就可以用 Xcode 打包编译了。

什么是 TVM Unity Compiler?

TVM Unity Compiler是 Apache TVM 项目中的一个新框架,旨在提供一套架构,将各种优势组合起来,以优化机器学习模型在不同硬件平台上的运行效率。TVM是一个端到端的机器学习编译框架,支持多种前端库如TensorFlow, Pytorch, MXNet, ONNX等。TVM Unity框架通过引入新的技术路线,如Relax语言和相关的代码,以及对注册对象的管理(Registry::Manager),来增强其编译能力。此外,TVM Unity还致力于构建跨层机器学习编译器基础设施(Cross-Layer Machine Learning Compiler Infrastructure),以进一步提升机器学习模型的编译效率和优化能力。这表明TVM Unity Compiler不仅仅是一个简单的编译器,而是一个综合性的框架,旨在通过技术创新和架构优化,推动机器学习模型在不同硬件上的高效部署和运行。

其他上层工具

先放一张全局架构图,可以从上帝视角先一窥概况。

端侧 LLM 大模型推理

Ollama

关键词:GO 实现命令行工具本地服务器

基于各种现有的推理框架构建的一个 LLM 集成平台、社区(比如 gguf 的模型就会使用  llama.cpp 来推理),只需安装一个命令即可在本地快速和 LLM 对话。同时还会在本地开启一个 server,方面其他 chat UI 接入。

端侧 LLM 大模型推理

技术原理

依赖llama.cpp, 把 LLM 跑在 macOS, Linux, and Windows,用 GO 实现。支持导入 gguf, PyTorch or Safetensors 模型。

核心看这个配置文件Modelfile,这个是 Ollama 里的唯一配置文件,所有模型权重、推理参数、提示词模板都写在这里,可以认为是 Ollama 里最重要的文件。

其中 gguf在 Ollama 内部直接使用 llama.cpp 推理了。PyTorch 和 Safetensors 模型需要步骤比较多,需要借助 llama.cpp 这个工具先转换一下。

具体转换步骤:

  1. 转化模型:python llm/llama.cpp/convert.py ./model --outtype f16 --outfile converted.bin  (半精度 f16)

  2. 量化模型:llm/llama.cpp/quantize converted.bin quantized.bin q4_0(int4 位)

  3. 编写ModelfileFROM quantized.bin

  4. 创建 Ollama modelollama create example -f Modelfile

然后你可以在命令行和这个转换后的模型对话了,或者在本地开一个REST API服务供其他应用使用,具体可以看 Github 主页。有了 API,因此市面就有很多 llama 的 GUI,例如:Ollama-SwiftUIenchantedchatbot-ui,生态就这么繁荣起来了。

端侧 LLM 大模型推理

Jan

关键词:TS/JSUI 体验流畅性能佳

同样也是基于 llama.cpp 的 UI,一个非常好用的本地推理 electron 客户端。可以变成本地服务器。(性能应该比 Ollama 差一点)。BTW,Jan 基于 llama.cpp 做了个本地推理引擎 Nitro, 兼容 OpenAI 的 API,支持队列和伸缩,简化了 llama.cpp 的接入不走,可以轻松地接入线上产品(prod-ready)。 

使用下来体验非常流畅,性能也没有损失,是目前我用下来最好的 llama.cpp UI。

端侧 LLM 大模型推理

LLMFarm

关键词:SwiftUI 界面体验流畅性能佳

同样是基于的 llama.cpp,封装了 Swift 接口,为 Apple 平台专门优化的客户端工程。支持 ggjtv3 (must have a .bin extension) 和 gguf (must have a .gguf extension) 格式的模型。

这个项目专门优化了 Apple 平台的表现,能够部署到上 iPhone、Mac 上。实测下来,通过 llama.cpp 里面自带的 swiftui 项目无法在 iPhone 上跑 qwen2-7b 的模型,表现为直接 OOM;但是使用 LLMFarm 跑 7b 至少可以跑起来(虽然只有0.71t/s)

总结

以上就是目前开源社区端侧大模型方面的现状记录。最终再用一句话总结下,目前的旗舰手机能勉强跑 7B 的模型但速度极慢,几乎不可用(据说国内荣耀、OPPO 3月发布会的新机已经支持 7B 推理了,推测:1. 做了软硬件深度优化 2. 模型做了量化)。目前(2024年3月)要满足日常需求,旗舰的配置跑 1.8B 是最稳定的。按 scalinglaw 到今年9月的新手机,理论上就可以跑 4B 的模型;明年(2025年3月)行业一起努努力,就可以稳定跑 7B 模型。

我眼中的 AI Native

作者 KittenYang
2024年6月13日 14:14
我眼中的 AI Native

Native 在这里是一个双关的词,它包含了两层意思:

  1. 土生土长的(Native Speaker): 指那些天生适应AI环境的产品、系统或人,它们在 AI 世界中长大,像母语者一样理解和使用 AI 工具和技术,对 AI 的运用和影响有着本能的理解。例如,AI Native 应用可能是专门为利用人工智能功能而设计的,它们充分利用了机器学习、自然语言处理等AI技术。

  2. 原生的/本地的(Native to the Technology): 另一层意思可以特指移动端。所以本文也会顺便聊一聊 AI 时代,移动端可以做些什么?

总的来说,"AI Native" 强调的都是以 AI 做为核心驱动去设计和开发应用,无论是指技术本身还是指移动端。

从 OpenAI 的使命说起

我们翻开 OpenAI 官网,很轻松地找到这家公司的使命与愿景 —— 让 AGI(通用人工智能)惠及全人类。

我眼中的 AI Native

看似简单的一句话,却是一个非常大且难的命题。我们不妨尝试来拆解一下。既然是通用的、还要惠及所有人的人工智能,那必定是和每个人生活中息息相关的。换句话说,这个 AGI 一定具备了一个自然人最底层的感知能力。

那么作为一个自然人,我们感知世界的能力有哪些呢?无非就是视觉、听觉、触觉。我们先不谈触觉。视觉、听觉映射到数字世界里的具体事物上,视觉的承载对象可以是图片、文字、视频;听觉对应的是声音。所以命题就转换成了如何理解这些数字世界的对象。只要理解了数字世界,就能理解真实世界,最终实现 AGI 惠及每一个人的目标。

所以再回过头来看 OpenAI 的历史时间线,从 GPT2 一直到 GPT4 解决了 AI 理解文字的问题;DALL·E 解决了理解图片的问题;Whisper 解决了理解语音的问题;而最近大火的 Sora 解决了 AI 理解视频的难题,完成了最后一块拼图。如果我们只是把 GPT4、Sora 看成是用来写小说、剪视频的工具,那格局就小了,这些只是它顺便能做到的事情,OpenAI 走的每一步都是为了那个终极目标 —— AGI。

我眼中的 AI Native

试想如果未来我们生产出了各种形态的机器人,这些机器人能「观察」流水线、「监控」突发事件、「识别」人类动作、「听懂」你的指令,这不就是 AI 真正影响了现实世界,做到惠及全人类了吗?(BTW,只要人类还是肉体,机器人会是下一个可以比肩 AI 的领域)

下面我们把时间尺度缩小到未来5年,看看目前的现状下,AI Native 可以往后延伸出一条什么样的时间线。

I. 业界现状

A. 技术进展

LangChain

https://www.langchain.com/

LangChain是一个专为开发由语言模型驱动的应用程序而设计的框架。它的核心理念是通过将不同的组件“链”在一起,组成一个 App。总的来说,LangChain是一个强大的框架,旨在简化构建基于大模型的AI应用程序的过程。

我眼中的 AI Native

AutoGPT(ReAct)

ReAct(推理(reasoning),行动(acting)) 最早来源于这篇论文 ReAct: Synergizing Reasoning and Acting in Language Models , 本质上还是一种 Prompt 技术。作者设计了简单的 wikipedia api(search, lookup, finish) 来通过的外部知识协助 LLM;在 call api 之前和之后,显性的放入 Thought 和 Observation,用来指导和调整 api 的调用策略;

我眼中的 AI Native

AutoGPT 则是把 ReAct 这一技术升级了一个工具。其运行原理基于自主运行的 ReAct 构建了一个系统,该系统无需或少需人工干预即可运行,能够根据 GPT 自主决策结果,同时结合外部资源执行相应操作,通过循环评估策略实时评估目标达成程度。项目地址:https://github.com/Significant-Gravitas/AutoGPT

llama.cpp 

https://github.com/ggerganov/llama.cpp

llama.cpp 是一个基于C/C++实现的工具,主要用于部署和推理大型语言模型(LLM),同时具有极高的性能,让端侧大模型成为可能。它提供了大模型量化的工具,可以将模型参数从32位浮点数转换为16位浮点数,甚至是8、4位整数,以适应不同的硬件环境。此外,llama.cpp 支持多种模型格式和量化方式,能够在CPU或GPU上运行。

Function Calling

这项技术允许模型在回答问题时,不仅依赖于自身的数据库知识,可以调用外部函数来获取更多信息或执行特定任务,从而实现更加丰富和准确的交互体验。

RAG

检索增强生成(Retrieval Augmented Generation, RAG)是一种结合了信息检索和自然语言生成的技术,旨在提高大型语言模型(LLM)的性能,使其能够更准确地理解用户的查询,并生成更符合用户需求的文本结果。RAG的核心原理包括信息检索和生成两个方面:信息检索用于从大量的文本数据中检索相关信息,而自然语言生成则用于根据检索结果生成自然语言文本。

RAG 的一个显著优势是它可以微调,这意味着不需要对整个模型进行重新训练,就可以有效地修改其内部知识。

Stable Diffusion

最为开源的文生图模型,Stable Diffusion 及各种变体已经可以媲美闭源的 Midjounery 了,包括各种 Lora,插件: SAM、ControlNet、Inpainting、无损放大,以及 ComfyUI 的节点式工作流,可以说已经非常成熟了,已经被设计师投入日常工作生产中,个人感觉比 copilot 之于程序员的革命性和效率提升更大。

我眼中的 AI Native

LLM

  • chatGPT

  • Claude

  • Llama(开源)

  • Gemma (开源)

  • Mistral 8x7b(开源)

  • 以及一众国产大模型,有点眼花缭乱了

声音

  • Whisper 及各种变体: TTS

  • GPT-SoVITS:语音克隆

视频

B. 功能应用

软件层面

Agent

Agent 这个概念其实早就有了,只是苦于之前没有 LLM 超强的语义理解能力。现在随着 LLM 崛起,agent 的概念又一次被搬上台面。简单来说,人们不满足于 LLM 简单的文字输出能力,而是希望利用它理解文字的能力,作为调度中枢,进一步控制下游的工具,从而连接起更大的系统。

我眼中的 AI Native

国内字节的 AI 低代码平台——Coze,通过可视化的方式编排节点,快速组装成一个特定场景下的 AI 工具。

国外的 Langflow、Flowise 则是目前 AI 低代码平台做的非常领先的两家。

【思考】:我判断此类工具最终的归属和苹果的快捷指令会很像,在某些场景下会非常方便快捷,但更多时候小白用户不会主动去创建,多是拿来主义,适合有动手能力的 Geek。而且这类平台开发没什么门槛,也没什么盈利手段,不是一块很大的蛋糕(类比现在的快捷指令市场)。但是 Agent 的思路还是大有可为,适合做在产品内部比如问小饿,我只是觉得这样的低代码编排平台蛋糕不会很大。

自动化测试

自从 LLM 解锁了读图能力后,就有人开始结合按键精灵尝试自动化测试了。其中包括腾讯的 AppAgent: 

三方应用: https://github.com/mnotgod96/AppAgent

这篇论文就是对 CoT 的一次实践,但是 CoT  目前最大的问题就是不可控,很容易走火入魔陷入死循环,需要实操过程中不断调整 prompt 和异常防护。

【思考】:用 AI 识图来做自动化可以说是比较确定的事情了,个人也比较看好。但其实类似的场景还有很多,比如帮助老人、视障人群操作智能机;不方便操作手机(比如开车、做菜)的时候,通过语音让 AI 自动操作。

前景值:⭐️⭐️⭐️☆☆

AI 搜索引擎

基于 RAG 原理诞生的 Lepton AI Search、perplexity.ai、秘塔AI搜索,也可以私有部署搭建一个专有领域文档答疑机器人。

下面是我用了一个月的用来平替 Google 的 AI 搜索神器 秘塔AI。他真的能帮我替代 Google 50% 的使用场景。它的原理也非常简单:

  1. 当你输入一个问题,它会借助 LLM 生成相关的十几个问题

  2. 通过 Bing、Google Seach API 搜索这十几个问题的答案

  3. 把所有答案汇总,再让 LLM 总结

最终,甚至还能给你输出一个脑图。如下,即使是昨天才发布的 Claude3,基于 RAG 的 AI 搜索引擎也能很好地回答。

我眼中的 AI Native

现在的 Agent 都会有一个模块叫 Retriever,中文可以翻译成读取器,意思就是可以读取你外部输入的资料。RAG 的两大好处:

  1. 你可以用口语化方式搜索。适合于记忆模糊的时候搜索。

  2. 可以获取最新的知识。

【思考】:非常有前景,可以预见将会大面积应用于论文解读、客服、导游、答疑等场景,并且技术难度很低(核心模块都封装好了)。钉钉文档、飞书非常实用用来做这个事。总结起来就是凡是目前需要搜索的地方,都可以用 RAG 的方案做优化(甚至替换)。

前景值:⭐️⭐️⭐️⭐️☆

硬件层面

AI 大模型手机

相较云端大模型,端侧大模型由于利用了手机终端的闲置算力资源,减少了数据传输,因此在很多场景下会更加高效、便宜、安全。在手机+大模型的竞争中,每一个厂商都不想掉队。

我眼中的 AI Native

荣耀

  • 破局者,率先在手机上运行70亿AI大模型

  • MagicOS 8.0

小米

  • 澎湃系列芯片

  • 运行13亿参数大模型 MiLM

vivo

  • BlueLM 蓝心大模型

  • V系列芯片,天玑9300支持最高330亿参数AI大模型

  • 首款AI大模型手机X100

OPPO

  • 马里亚纳系列芯片

华为

联发科

  • 天玑9300支持端侧运行最高330亿参数AI大模型

高通

苹果

  • iOS18将加入AI功能

三星

  • 三星手机在全新的S24系列中加入了AI大模型

为了实现大模型体验和手机性能的平衡,厂商们目前普遍采取了“端云协同”的策略,同时部署端侧和云端两种模型,根据不同的应用场景和需求来进行选择。端云协同可以最大化地发挥“端侧快”和“云侧强”的优势,同时还能解决信息安全隐患、云端算力成本过高等问题,可以说是现阶段打造大模型手机的最优解

AI Pin

实时翻译识别食物、智能助手,通过结合AI技术、传感器和投影仪,为用户提供多种自然直观的交互功能。

我眼中的 AI Native

景区 AI 导游

传统的讲解器,只是一个耳机和录制好的音频,未来会出现可以自动定位讲解、深入解答用户问题的 AI 设备。

火火兔

着眼于儿童玩具市场。把传统的玩具接入 LLM 大模型,可以更智能地和儿童对话。

我眼中的 AI Native

待办墨水屏

通过魔改超市淘汰下来的墨水屏,LLM 可以每天更新一条格言,或者把你待办事项同步显示到上面。

我眼中的 AI Native

每日相框 

把传统的相框,接入了 Stable Diffusion 服务,每天早上自动更新一张 AI 生成的图,让你的相框每天都不一样。

我眼中的 AI Native

【思考】:边缘计算是趋势,类似于过去安卓系统渗透到各种嵌入式设备的思路,未来一些特定场景下的 AI 设备也会占有一席之地。类似与 NAS、树莓派、电视盒子这些外设,底层逻辑还是把一部分功能剥离出来,变成一个独立的外设。而且思路不一定要局限于 to C,to B 也大有可为。比如池塘边监控用的摄像头增加 AI 理解视频的能力,就能在发现有人落水的第一时间鸣笛、报警;农产品分拣流水线通过 AI 实时分类大中小等等.... 

工业进展

英伟达 GTC 2024:

  1. 机器人

机器人一定是未来的趋势;就好比光有了聪明的脑子,不能只用来聊天吧。只要人类还是肉身,我们就依赖物理世界,那么让 AI 改善我们的物理世界就是顺理成章的需求。比如工厂流水线、自动驾驶、机器人宠物…… 

  1. 扩大市占率

目前 GPU 业务严重依赖谷歌云、OpenAI、Azure、AWS 等几大云厂商,而这几大云厂商也在自研芯片。与此同时,随着人才流转、AMD和英特尔追赶,英伟达的算力优势一定会逐渐蚕食,前有夹击,后有追兵。所以英伟达必须需要扩大生意伙伴。比如这届 GTC 可以看到 NVIDIA DRIVE Thor 和国内多家汽车厂商合作自动驾驶、联想与英伟达宣布合作推出全新混合人工智能解决方案、九号公司与英伟达展开了机器人领域的合作等。

  1. SaaS

纯卖 GPU 的生意不会长久。第一随着人才被挖竞对追赶,GPU 的算力优势一定会逐渐蚕食;第二,GPU 业务严重依赖谷歌云、OpenAI、Azure、AWS 几大云厂商,需要扩大生意伙伴;第三,GPU 算力的增长远超 AI 产品的增长,换句话说,没有那么多模型要训练了。

因此,发展软件应用生态是英伟达的必然之路,本届 GTC 英伟达大力宣传自己在软件方面的布局:机器人开发的仿真环境、AI 模型和工作流、药物研发、基因组学分析、视频分析

我们的一个猜测,未来 AI 会越来越渗透到我们身边的终端设备上,比如门禁闸机、景区导游、具象机器人、翻译笔、全屋智能、车机等,所以终端上沉淀 LLM on Device 的经验是一个重要的工作。

II. AI Native:重新定义智能应用

A. AI Native 的概念阐述

AI 原生应用(AI Native)是一种以 AI 技术做为核心驱动力的应用,使其在代码层面和应用架构上与 AI 技术深度融合。AI 就像是 App 的血液,流淌在应用里的每个角落。它的设计应遵循用户无感知的原则,即AI技术在后台悄无声息地运行,为用户提供自然流畅、如同真人般的交互体验。

既然是核心驱动力,我们斗胆给个量化的数据,核心链路和功能超过 60% 有 AI 参与的应用,我们可以认为是达到了 AI Native 的标准。

B. AI Native 案例

我们眼中可以称之为 AI Native 的案例。前些年风靡过一个词叫「次时代」,我觉得 AI 时代这个词会再度翻红,越来越多的应用会出现「次时代」的革命性体验。而这个过程,会是一个以点及面、星火燎原的过程。

我们认为目前的传统应用会通过一个个 AI 闪光点切入,一点点把 AI 能力融入现有场景,直到转变成 AI Native 应用。罗马不是一天建成的,从 AI 小功能开始一点点做起,日拱一卒方为可行之道。

以下是一些我们认为可以称之为「次时代」 的 AI 闪光点,虽然都是小功能,但具备 AI Native 的特质。

Runway

  • 物体消除、物体追踪

以往后期领域需要一帧一帧抠图,或是自动追踪能力很差,现在有了 AI 加持可以既快又好地解决。

我眼中的 AI Native

剪映/CapCut

  • 自动绿幕抠像

  • 自动加字幕

  • 自动旁白合成

同样是需要后期大量繁琐重复的劳动,现在可以轻松优雅的解决。

HeyGen

AI 数字人。输入文案,自动对口型。适用于新闻主播、市场营销和广告宣传等。

我眼中的 AI Native

闪念胶囊

工作生活中凡是需要立刻记录的信息,可以通过长按侧键语音输入,AI 会自动帮你分类、总结、写入对应的应用、生成排版等。你只管记录,剩下的交给 AI。

Touch And Talk

这个功能来源于前几年罗永浩的 TNT,虽然当时被喷得体无完肤,但是回过头看,竟然有不少功能和交互和 AI 的契合点都非常好。

具体的交互是:按住屏幕上的元素,说出你的指令,AI 自动帮你完成任务。比如:

  • 收到微信:“明天记得新华书店带一本 AI 的书”,你就可以长按说出指令:“把这个事情加入日历,下午6点",AI 就会自动在你的日历里创建一条待办。

  • 新手面对 Excel 里茫茫多的功能无从下手,按住表格直接说出你的需求:“我想把这一列排序;我想把这个标题加粗;我想算出这一行平均值....”

这些当年看起来很难实现的交互,现在有了 AI 的加持都可以很好地解决。

AI 会议纪要(钉钉、飞书)

精确转录出文字稿,生成大纲,点击大纲还可以展开细节,甚至还有 TODO List。

「多选一」

这个灵感来源于 Midjourney,我们在 MJ 里输入一段 Prompt,它会返回给你 4 个候选图,你可以选择一个让它再按照这个风格往下迭代一组候选图。

这种「多选一」的交互逻辑非常值得借鉴。因为 AI 本来就会存在一个创意值,而 Prompt 又是一项专业的工作并非人人都能精确描述,那么通过一次性给他几个候选值选择,通过和用户的来回交互一点点缩小范围,直到找到心里想要的效果。这种交互方式,我们认为会是未来 AI UGC 领域通用的交互手段。举个例子,你只需要把文案一股脑输入 PPT,PPT 会自动帮你创建几套精美的排版供你选择,你选择一套后 AI 会继续优化,直到你满意为止。

C. 对比传统应用,AI Native 的优势

对比传统应用,突出AI Native的优势主要包括以下几点:

  1. 高效率:AI Native 应用能够自动地处理和分析大量数据,远超人类的能力,从而从大数据中提取有价值的信息,提高工作效率

  2. 智能决策支持:通过对大量数据的分析,AI 能够帮助企业和组织做出更好的决策,尤其在商业、医疗等领域,这具有极大的价值

  3. 智能化:AI Native 将人工智能算法和模型直接嵌入到应用程序中,使得应用程序具备智能化、自动化和高效化的能力

  4. 原生为 AI 而设计:应用程序从设计之初即考虑到 AI 的应用和能力,原生为 AI 而设计,充分利用和发挥 AI 大模型的智能优势,提高应用程序的智能化水平

  5. 以AI能力为基础设计:AI Native是以AI能力为基础去设计的产品,利用人工智能技术实现业务流程和服务,与传统应用的交互设计上可能会有本质不同

III. 实现 AI Native 应用的构建要素

A. 技术基础设施

构建 AI Native 应用的基础首先依赖于强大的数据集与训练平台。高质量、多元化的数据集是驱动AI模型学习和理解世界的关键,它涵盖了视觉、听觉、文本等多种类型的数据,确保模型能够全面模拟人类感知能力。而高效的训练平台则为大规模深度学习模型的训练提供算力支持,如分布式训练系统、高性能GPU集群等,使得模型能够在较短时间内达到理想的性能水平。

数据集与训练平台

就像 AWS、Azure、阿里云构建了移动互联网时代的底座,AI 时代也会出现一大批 Infra 底座。我们认为新一代的训练平台一定是开箱即用,简化训练过程,让开发者能够高效地进行基准测试和训练模型。

  1. 内置 PyTorch、Tensoflow、Axolotl、Stable Diffusion 等常用的模板环境,内置常用 ImageNet 、CommonCrawl、Wikipedia 数据集,开发者只需单击几下即可获得完全配置的开发工作区。

  2. 开发者更少关注 ML 运维操作,更多地关注应用程序的逻辑。

模型库与 API 服务

  1. 模型平台,国内有魔搭,国外有 HuggingFace,可以一键带入训练平台二次开发,允许开发者在平台上进行模型微调、迁移学习等操作。

  2. 训练平台支持一键部署生成 Serverless API,按需计费,弹性扩容,使得开发者可以便捷地将先进的 AI 技术集成到应用程序中。

B. 用户体验创新

这一步需要产品经理和开发人员集思广益思考应用场景和用户需求,我觉得一个最好的办法就是现有技术都用一遍,有了切身体会才会有新的思路。

目前想到的点包括:

全局助手入口

常驻页面右下角,随时待命的小助手,作为万能入口兜底。

优化现有交互动线

用户大多数时间还是保留原有使用习惯,所以在不破坏用户现有动线的前提下,把 AI 能力「润物细无声」地融合进入,会是未来很长一段时间各大 App 都会做的事情。

举几个例子:

  1. 用户选中一段文字,自动弹出键盘可以输入指令:「续写、翻译、文字加粗....」

  2. 网上看到一张图,长按后语音输入「识别出文字然后添加到待办事项」

UGC 链路,从「写」到「选」

凡是目前需要用户创作的地方,现在都是让用户从0开始创作,未来都可以把这一范式从「写」升级到「选」。所谓的「选」就是开局直接给用户几个模板,让用户先大致选一个风格,然后基于这个风格再优化几个模板,以此类推,不断缩小范围,直到生成用户心中的那个答案。以下是一些常见的 UGC 领域:

  1. 写评价

  2. PPT 排版

  3. 润色文案

  4. 视频剪辑

  5. 配图(插画、营销号、技术架构图等)

实时性与边缘计算

新的终端

车机、手表、智能眼镜等创新终端或许可以成为新的突破口,既然是新的终端了,可以选择激进点,做一个纯 AI 驱动的 App,纯语音交互,功能简化成只能点外卖,打的就是一个 AI 点餐心智。

大模型下放

随着边缘计算的发展,AI 大模型在终端设备上的实时处理能力得到提升。大模型端侧推理是必然趋势,手机作为现代数字生活里绝对的中枢(且未来很长一段时间内都是),自然是运行大模型最理想的平台。目前国内安卓厂商里的荣耀、OPPO 已经把 7B 的大模型塞入了手机端,且在手机上实时推理无需联网,已经证实了技术上的可行性。

以此为衍生,任何智能设备理论上都有塞入大模型的可能。

C. 遵循伦理规范与安全保障

在构建AI Native应用的过程中,必须严格遵守相关法律法规,关注隐私保护、数据安全及伦理道德问题,确保AI技术的发展不会侵犯用户的权益或对社会造成不良影响。

综上所述,从基础架构建设、技术创新融合到设计原则、伦理规范等方面全方位布局,才能有效推动AI Native应用的构建与发展,最终实现AGI惠及全人类的愿景,并在各个领域带来革命性的用户体验与价值提升。

总结

我们正处于一个 AI 一日千里的时代,科技的迅猛发展正以前所未有的力量推动着社会进步。随着人工智能、大数据、云计算等前沿技术的深度融合与应用,「次时代」正在缓缓展开。

面对浪潮,我们只有站在潮头才不会被拍在沙滩上。好消息是,我们坚信我们的世界会变得越来越美好,随着更多 AI Native 应用的涌现,我们的工作生活一定会迎来翻天覆地的改变,想到自己是其中参与改造的一员,还是有点使命感和激动的。

「小K中国行」期中总结

作者 KittenYang
2018年6月22日 01:28
「小K中国行」期中总结

自从小K 2017年12月3号“离家出走”迈出为期一年的「环中国行」的第一步到现在,除去中途回家过年的小半个月时间,行程已经 6 个月有余。某个晚上,iPhone Photo App 突然推送了一条“你有新的回忆”的通知,我顺势一划,要不怎么说大家都喜欢苹果产品呢,伴随着内置的 BGM ,一幅幅自己在全国各地的照片,一张张和路上朋友的合影,一幕幕回忆像潮水般涌上心头,一顿劈头盖脸的回忆杀让我文思如泉涌。虽然我原计划会在旅行结束之后把这一年的经历做成纪录片,每天也都坚持着写日记的习惯,但是此时此刻我的情绪被完全点燃了,我已经等不到旅行结束的那天了,本着不想浪费这次意外到来的感动的初衷,我决定给这半年旅行做个期中总结。

1. 一共去了多少个城市?

我统计了一下,不包括那些临时停留点,只包括上过街头体味过当地民风的地方。一共有 11 个省份,59 个城市和乡镇。

  • 安徽省(2):
    • 合肥市
    • 黄山市 「小K中国行」期中总结

  • 河南省(2)
    • 洛阳市
    • 登封市

  • 山东省(5)

    • 青岛市 「小K中国行」期中总结
    • 烟台市
    • 蓬莱市
    • 济南市 「小K中国行」期中总结

    • 泰安市 「小K中国行」期中总结


  • 吉林省(3)

    • 长春市 「小K中国行」期中总结

    • 吉林市

    • 白山市 「小K中国行」期中总结


  • 黑龙江省(6)

    • 牡丹江市
    • 五常市 「小K中国行」期中总结

    • 哈尔滨市 「小K中国行」期中总结

    • 抚远市 「小K中国行」期中总结

    • 佳木斯市

    • 漠河市 「小K中国行」期中总结

  • 北京市 「小K中国行」期中总结

  • 天津市 「小K中国行」期中总结

  • 云南省(15)

    • 昆明市
    • 己衣 「小K中国行」期中总结

    • 元谋 「小K中国行」期中总结

    • 广南

    • 文山
    • 蒙自
    • 红河 「小K中国行」期中总结

    • 元阳

    • 西双版纳·景洪
    • 丽江 「小K中国行」期中总结

    • 大理 「小K中国行」期中总结

    • 泸水

    • 福贡 「小K中国行」期中总结

    • 贡山 「小K中国行」期中总结

    • 丙中洛 「小K中国行」期中总结


  • 西藏(12)

    • 察瓦龙 「小K中国行」期中总结

    • 左贡

    • 八宿 「小K中国行」期中总结

    • 然乌 「小K中国行」期中总结

    • 波密 「小K中国行」期中总结

    • 林芝 「小K中国行」期中总结

    • 拉萨 「小K中国行」期中总结

    • 日喀则 「小K中国行」期中总结

    • 普兰县 「小K中国行」期中总结

    • 札达镇 「小K中国行」期中总结

    • 珠峰大本营 「小K中国行」期中总结

    • 纳木错 「小K中国行」期中总结


  • 四川省(4)

    • 成都 「小K中国行」期中总结

    • 乐山

    • 峨眉山

    • 彭州 「小K中国行」期中总结


  • 新疆(6)

    • 乌鲁木齐 「小K中国行」期中总结

    • 奎屯市

    • 伊犁 「小K中国行」期中总结

    • 巴音布鲁克

    • 库车 「小K中国行」期中总结

    • 巴音郭楞


2. 小K和他的朋友们

旅行收获的不仅是沿途的风景,还有路上的同伴。在这出来的大半年的时间,留下了不少印象深刻的朋友。

  • 安子,一个专注于边境旅游的独立领队。经常关注我的人肯定不会陌生了,我和安子可以说已经是挚交了,完全把彼此当成兄弟一样。我们结识于黄山市的阳产土楼,当时我走在上山的盘山公路上,安子坐着自己包的面包车从后面超过了我,我嫌车费贵就没坐,但是安子主动说你上来吧,你不知道上去有多远。就这样,差点错过的相识因为安子的主动提议,才让我们有了联系,才有了后面发生的故事。你想一个让大妈们跟团跟了第一次还想跟第二次第三次的小伙子,得待人和善,处事体贴到什么地步才行。我跟安子性格很像,所以一聊起来就像认识很久的朋友。后面我们一起走了东北线,在哈尔滨一起学单板滑雪,去抚远跨年,走了滇藏线,还一起拍了一档纪录片叫《不荒此行》,从大理出发,一路沿着怒江北上,搭车、拼车、徒步,深入人迹罕至的村落,最终达到拉萨。整天吃在一起睡在一起,无话不谈,说是挚交一点都不为过。 「小K中国行」期中总结

  • 安子当时正好有个东北线的团,把我顺带捎上了,这是我们的司机关哥,关哥是满族人,心眼好,正直老实,不忽悠人,这是我在东北认识的第一个东北人,留下了很好的印象。 「小K中国行」期中总结

  • 黄山昆仑青旅认识的张哥,当时给我留下印象最深的两个标签就是:一辆小面包行走中国,一个愤青,额,愤中年吧。有一件事情我印象很深,就是张哥走访并拍摄了好多尘肺病人的访谈。图中我们在昆仑做当晚的晚饭。啊,这里顺便安利一下黄山昆仑国际青年旅社,到目前为止依然是我这半年以来住过最好的青旅!注意,没有之一!(小鱼姐快给我打5毛) 「小K中国行」期中总结

  • Jeff,新加坡人,和我一样,也是94年的同龄人。我们在黄山相识,性格爱好都很像,所以聊起天就像认识很久的朋友,于是很快就打成一片。Jeff 中文不太好,所以我跟他基本都是英语交流。我们一起爬了黄山,后来又在青岛玩了4天,在哈尔滨他的另外两个新加坡朋友也来了,一起又玩了2天。分别的时候,我说咱们下次新加坡见。 「小K中国行」期中总结

  • 一对来自上海的老夫妇。当时在浪巴铺土林,看我一个人,叔叔阿姨们说你跟我们拼一间房吧,你就说是我们的孩子,你也可以省一点钱。我还是挺佩服叔叔阿姨的,同样是退休了,但从来不报团,都是自己做的攻略。我问叔叔你是上网看的吗?叔叔说自己不会上网,都是去新华书店看书获取攻略的。因为浪巴铺土林是个很小众的景点,马蜂窝上也只有很少的篇幅介绍这里,实际前往更是要倒好几班车才能到这里。当时我们很佩服这对老夫妇的。 「小K中国行」期中总结

  • 独龙江支教老师。在独龙江唯一一所一贯制学校里我们遇到了两位来自云南大学的支教老师。从他们口中知道由于政府的扶贫政策,独龙江的教育一点都不落下。当我以为她们的主要工作应该就是教书的时候,她们说并不是。山里的孩子,比知识更需要的,是心里的建设。因为他们从来没有见过外面的世界,突然打开了大门,有些孩子可能会因为心里落差而自卑,甚至做出一些无法挽回的事情。

「小K中国行」期中总结

  • 这是我和安子在独龙江遇到的搭车司机,来这边负责当地的电力维护,独龙江曾经是个与世隔绝的地方,也是中国最后一个进入社会主义的乡镇。关于独龙江我们专门做了一期节目,B站搜索 《不荒此行》,第三集 「小K中国行」期中总结

  • 刘浪。第一眼有没有觉得很像房祖名或者张默?来自丹东的帅小伙,和我同龄,大四快毕业了,一个人说走就走,从丹东一路搭车来到西藏。比大四的我厉害多了。我们在波密相识,一起看了桃花,一起幸运地见到了南迦巴瓦峰真容,还一起过了命地从原始森林里逃了出来。 「小K中国行」期中总结

  • 扎西才巴。西安交大的高材生。从小在内地读的书。我们当时在林芝卓龙沟,三个人想问问有没有车可以有偿带我们上去。就遇到了正在准备婚事的才巴大哥。才巴大哥说不好意思没有车,但是很热情地放下了手头的活儿把我们请到客厅,给我们倒酥油茶喝。我们被这样突如其来的热情惊到了,第一次进原汁原味的藏民家里,问了好多,才巴大哥也说了好多。 「小K中国行」期中总结

  • 在卓龙沟,我们三个人误入了原始森林,找了半天才找到远处的盘山公路,费了好大劲儿才从杀出一条求生之路。但此时我们已是精疲力尽。天无绝人之路,就在我们都打算原路返回的时候,突然看到前往有几辆车,再往前走近一看,原来是一大家子藏民围坐在一起举行家庭聚餐。我们太饿了试着问了问能不能施舍点东西吃。藏民们知道我们的来意,二话不说邀请我们加入他们的聚餐,牦牛肉,大饼,饮料,面包,零食。那一刻我真的感受到了民族一家亲。 「小K中国行」期中总结

  • 这是我们从然乌搭我们到波密的阿旺哥。当时我和安子在然乌 318 国道上分开搭车,我在后面,他在前面,我搭到了阿旺哥的这辆车,一般搭车我们对那些豪车是不抱什么希望的,但是当这辆本田 SUV 停下来的那一刻,我是吃惊的。当我坐上这辆车更是吃惊,内饰豪华整齐,以至于我都不好意思上车,一个劲儿地说不好意思弄脏您的车了。但是阿旺哥一点也不介意,说没事没事,擦擦就行了,还给我们喝饮料。阿旺哥有个女儿,我相信他的女儿一定很幸福。 「小K中国行」期中总结

  • 这是从波密搭我到林芝的来自四川遂宁的夫妇,也是一上车就给我塞面包塞饼干。感动到语无伦次,都忘了问夫妇称呼。聊天中知道他们是去林芝做生意,也是第一次来林芝。这是我们在唐古拉山口合的一张影。 「小K中国行」期中总结

  • 这是我到拉萨前的最后一程。也是搭车。搭上了一辆大货。这也是我第一次坐大货。这么大的家伙要停下来都不容易,但是司机师傅看到我竖了大拇指竟然停了下来,让我非常意外和感动。王大哥,兰州人,常年在兰州、拉萨、乌鲁木齐跑车。车子后面还有个大通铺,睡着他的换班伙计,一辆车,一个白天开,一个晚上开,日夜兼程,开大车的司机真的很辛苦。请司机师傅们下个趟馆子,师傅说自己好久没吃到这么丰盛的饭了,平时都是吃了这顿没下顿,所以干这行的基本都落下了胃病。我拍下了这张合影,意外地发现自己已经这么黑了。标准的进藏后的脸。

「小K中国行」期中总结

  • 阿里北线8日游的拼车小伙伴。去北线除了自驾之外只能拼车了。这里推荐拉萨平措康桑青年旅舍,有全拉萨最大的旅游部,拼车方便,住宿条件好。 「小K中国行」期中总结

  • 来自日喀则的洛桑大哥,大学在华中科技大学读的计算机,现在在日喀则政府机关工作。为了躲避相亲一个来拉萨玩。我也是第一次知道因为你懂得原因藏族朋友如果入党了就必须放弃信仰了,而且平时不能出现在寺庙附近。另外我也发现在内地接受过教育的藏族朋友特别容易沟通。我记得特别清楚,当时我和洛桑哥走在马路上,他说了一个词“路怒症”,把我惊到了。我一开始担心的交流上会有障碍的顾虑完全消除了。 「小K中国行」期中总结

  • 在安集海大峡谷附近的一个村子找到的唯一一家提供食宿的农家乐,老人年轻时是军人,现在已经60岁了,不太会说中文,但是看到我们很热情,还很乐意过来和我们合影,第一张过曝了,我们说可以不可以再来一张,老人也没有不耐烦,于是有了下面这张合影。 「小K中国行」期中总结

  • 和祎哥,悦哥自驾新疆。祎哥和悦哥都是山西人,讲话贼逗。我们仨因为一个共同的爱好 ———— 摄影促成了这次新疆行。 「小K中国行」期中总结

3. 小K一共拍的照片

出来没几天,我的尼康 D5200 就在黄山顶上拍延时中途被风吹翻了,只听见一阵镜头玻璃破碎的声音,我就知道完了。不过正所谓不破不立,于是就有了我的 Sony A7M2,顺其自然地开始学习了风光摄影,然后就是疯狂追欧美的自然风光摄影风格,模仿着拍了一系列作品。相机 SD 卡里照片编号已经破 10000 了。限于篇幅有限,我就不在这里贴出来了,大伙可以去我的 图虫主页 查看所有摄影。

「小K中国行」期中总结


4. 最喜欢的省份

西藏!

风景美就不用说了。世界屋脊,一众八千多米的雪山,大大小小的措。来西藏你看到的都是独一无二的美景。而让我最留恋最感动的,还是在西藏遇到的当地人。同样是藏区,川西和西藏简直就是一个地狱一个天堂。川西山区的当地人(牛背山、红岩顶)恶劣程度不亚于雪乡。然而在西藏,可以这么说,我遇到的每一个非生意人的藏族朋友,无不热情友善。我想这和这里全民信教有很大关系。我一个从来不信宗教一直认为宗教是“奴役”人民的工具的人,在西藏接触了这么久的藏传佛教,看过这么多磕长头的信奉者以至于到后面都习以为常,都开始尝试去了解一点藏传佛教的历史。还有这里特别漂亮统一识别性强的建筑,在西藏待了24天,周围全是样式统一的建筑,以至于现在离开西藏了,只要一看到这些风格的建筑,时光立刻穿梭回到我在西藏的时候,想起的都是遇到的藏民带给我的感动。


5.最喜欢的城市

成都!

我认为的衡量一个城市的好坏,首先应该是现代化,这一点成都作为新一线城市绝对没有问题。来春熙路太古里之前,我以为十一的上海外滩、南京路叫人多,来春熙路太古里之后,我才知道这里天天是十一。各种数码产品店,奢侈品店,大牌小牌一应俱全,没有你买不到的东西只有你想不到的东西。然后是吃的,这个我就不用说了,是个中国人都知道成都美食无论种类丰富程度还是好吃程度敢称第二没人敢称第一。在这里唯一能限制你对美食的欲望就是你的胃已经撑了。自然景观,出城区70公里,自然资源丰富,立刻让你体会到大自然的力量。长假自驾新疆、西藏、青海任你选。什么?高原风光看腻了?往南走云南,贵州,重庆了解一下。最后,由于地处盆地,常年出太阳的日子少,紫外线也少,所以四川妹子皮肤普遍白皙细腻,常言道,一白遮三丑,再加上现在的姑娘都还不错的穿搭水准和东方神秘古国流行的化妆术,只要正常身材的看起来都不差。结论就是,以后要是移不了民,我就在成都定居了。


6. 喜欢的美食

  • 云南铜瓢牛肉火锅
  • 蓬莱小面
  • 四川麻糍冰粉
  • 老北京卤煮
  • 西双版纳芒果、释迦
  • 贵州水城羊肉米线
  • 东北喜家德水饺
  • 新疆烤馕
  • 乌鲁木齐辣风芹
  • 成都双流兔头
  • 丽江腊排骨

记不清了.....


暂时就写这么多吧。半年的时间已经过去了,拍了好多素材,2T的硬盘已接近饱和,下半年的行程我得再准备一块硬盘了,还好每天都有写日记,到时候看到这些文字就能拾起回忆。想分享的太多,想说的话更多,一切的一切我都放在我的纪录片里吧,到时候《小K中国行》里有我这一年的全部。

地图上也打了不少点,然而还没有过半。昨天是夏至,这意味着漫长的夏季开始了,这也是中国最美的季节。接下去的旅程从青海开始,在此之前,青海省在我心中一直以出镜率最低以至于都快被我忘记的省份存在着,现在让我来一探究竟吧。 「小K中国行」期中总结

在这个人生的重要节点上,我想停下来做个记号

作者 KittenYang
2017年12月1日 01:03

自从五月初辞职到现在,已有大半年没有上班的经历了,一直在准备人生规划中必做的一件事,在当初辞职时许下的愿景即将兑现的今天,感慨万千,终于要上路了,在转身回顾走过的脚印的同时,我觉得有必要停下来做个记号。

时间回到一年半前,那时正值毕业,金黄的阳光,碧绿的操场,悬挂着不同垂布的学士服,那是我对青春最后的记忆。我像一尾鱼群里的小鱼,随波逐流跟着浪潮的方向前进,即使有逆流而上的念头,但还是对抗不了滚滚向前的大势。 即使我和每个同龄人一样,都不想庸庸碌碌上班一辈子,也曾想过创业,也想过改变世界,但这些寝室里的豪言壮语都随着摆在眼前的房租、伙食费、买车买房的现实压力以及自身能力的问题成为了记忆里的幼稚证据,为了生存,为了不甘一毕业就回老家的好胜面子,我们被社会磨平了棱角,成为了一个个魔都的上班族,地铁的常客。

当你失去自由的时候,你才会对自由更加渴望。大学看的一部纪录片——《搭车去柏林》无疑是这个想法的源头,然而没有太多资本,所以只能默默种下这个愿景,工作努力一年,辞职走遍中国。我人生中那些特别强烈地认为这辈子一定要做的事情不多,但这就算是其中一件。

就这样我在公司按部就班呆了一年。

大公司可能是人生段落的中止点,大多数同龄人忙着刷 offer 进大公司,在中国哪哪都是军备竞赛,想着怎样在30岁之前升职,4、50岁时挣够钱提前退休,想象着所拥有的一切是一栋房子,几台车子,一个老婆,几个孩子,住进约翰·契佛笔下的中产阶级社区“绿荫山”,无望地回忆青春…… 虽然每个人的生活方式不同,我应该保持尊重的态度,但我觉得有些事情还是有社会通识的,我觉得那样很没意思,我很怕这一切复制到我身上。我这么年轻,就要开始按部就班、一眼未来得生活,这和我一直以来都想和别人不一样的性格严重不符。

辞职之后按照我的计划,先用几个月时间把可持续收入这条高速公路打通,马斯洛需求层次理论告诉我们经济是基础,其他的都是上层建筑。虽然工作一年有了些积蓄,但我还是想试着可持续发展,毕竟这一趟下来怎么说都得大半年吧。软件行业的一个特点就是天生带有“被动技能”,当你完成一个作品上架之后,理论上它可以24小时为你带来收益。互联网的可复制性让卖拷贝这种盈利方式的效率变得前所未有地最大化。虽然类似 App Store 这种分发平台才是最大的赚钱机器,但开发者都应该感谢,没有这些平台我们连 70% 都没有,大不了就当只有 70% 的销量好了。关于自由职业工作方面的一些事我以后打算专门做个总结。

度过了3个月的开发期,靠着“余粮”活了下来,然后又花了两个月去考了驾照,终于到了该上路的时候了。

我曾经思考过一个问题,一个人类经典而且永恒的问题, Why am I? 我们活着的意义是什么?别担心,前方没有鸡汤预警。在经过不同时期不同答案的更替之后,最终我在这两年得出了一个基本稳定的答案——为这个世界留下痕迹,创造有长远影响的的价值。比如拍一部让人思考的电影,作一首美妙动心的乐曲,画一副壮美秀丽的山水画,写一款让人开心的游戏,成为球星,成为金融大鳄,成为一段历史的风云人物… 这也是为什么我想在没有任何负担的时候走一遍中国的原因,'cause most of us ,终其一生只能悄悄地来悄悄地离开,哪怕给自己的孩子介绍自己时,都没有一点可以“炫耀的资本”。

我不想给我这次出行带入太多游玩的成分,因为旅游往往是给人一种没有感悟走马观花式的消遣的感觉,我的初衷也并不是旅游,我讨厌商业化的景点。我对自己的国家了解太少,基本都只停留在教科书上,就像全中国有14亿这个人尽皆知的国情,我也只是在节假日才能感受到。我非常想去感受各地的人文风俗,想了解当地的历史,听当地人的生活故事,和邂逅的旅人分享自己的旅程,结交各地小伙伴,打开心扉,解放天性,完成一部完整的纪录片。另外我想以一种边工作边旅居的方式完成这次远行,为此我曾特地跑去俄罗斯做了一次“模拟测试”,我尝试在等车、晚上等有大把空闲的时间用来工作,以住青旅、短租等节省开支的形式解决住宿问题,我的结论是完全可以长期推广,所以我也会在这次远行途中产出一些工作上的成果。

年轻最大的资本就是浪费得起,我在我的博客首页位置一直放着一句话:Better late than never. 永远不要担心来不及。我并不担心什么浪费职场这宝贵的一年会赶不上别人,没有人规定成功的标准,我只知道这是我想要的生活,即使最终没有完成这个计划,我也算是对自己有个交代。

最后用一句我很喜欢的话结尾吧,“有些事情不去做,一辈子也不会去做了” —— 纪录片《搭车去柏林》

我们路上见。

智能家居实践(番外篇)—— 接入 HomeKit 实现用 Siri 控制家电

作者 KittenYang
2017年3月27日 00:38

前面我写了一个系列共三篇的智能家居实践,用的是 Amazon Echo 实现语音控制,但是 Amazon Echo 用户群体太小而且这玩意并没有在中国上市,日常使用中也是各种水土不服,让很多朋友有心无力。然而,正如你早就看到的标题中说的那样,我们还有更容易获得的工具,那就是 Siri。

自从苹果推出了 HomeKit 以来,鉴于苹果庞大的用户量,不断开始有家电厂商开发出兼容 HomeKit 的家电。然而第一个吃螃蟹的人总是有代价的,这些电器的价格不是太贵就是中国买不到,所以使用 HomeKit 的仍然是小众群体。

通过 HomeAssistant 我们实现了把普通家电接到同一个平台,并且实现了 Amazon Echo 进行语音控制,能否把 Amazon Echo 替换成 Siri 呢?答案当然是可以的,不然就不会有这篇文章了。

这回又是美帝的极客站出来拯救世界,隆重介绍这个重量级的开源库:homebridge,通过逆向 HomeKit 协议让普通的 Wifi 设备也能接入 HomeKit 从而通过 Siri 控制。你可以这里找到所有 homebridge 相关的 plugin,已经有超过500个了。

所以 homebridge 诞生之初和 HomeAssistant 并没有关系,但你可能注意到了,如果你每一个设备都安装一个 homebridge 相关的 plugin,太分散也不利于管理,所以,最好的办法是,把一个平台整体迁移过来。毋庸置疑,HomeAssistant 是目前管理智能家居最成熟也是最流行的平台,所以你只管把电器设备加到 HomeAssistant 就行,和 HomeBridge 只需要一个 Plugin 连接就行,这个 Plugin 就是 homebridge-homeassistant ,它在 HomeAssistant 和 HomeKit 之间架起了一座桥梁,让 HomeBridge 可以直接使用 HomeAssistant 平台下的所有设备。所以大致的架构图是这个样子的:

HomeBridge 的核心是 HAP-NodeJS 这个框架,用 NodeJS 模拟了一个 HomeKit Accessory Server 。作者 KhaosT 是个在美留学的中国人,曾在苹果的 HomeKit 团队实习过,这也 make sense 了为何是他第一个逆向了苹果的 HomeKit 协议。这里面有个小八卦,当 KhaosT 逆向了 HomeKit 的时候写了篇博客,但由于涉及到商业机密被苹果法务要求删除文章,但好在代码已经早就 fork 开了所以代码才得以流传到现在。试想要是当初代码没有开源,恐怕我们现在还享受不到这一成果。

其实我上面告诉你有 homebridge-homeassistant 这个东西已经可以了,剩下的无非就是看 README 跟着做的事情。所以我不想把安装过程再复制粘贴一遍,我就说一下安装完之后如何和 HomeAssistant 桥接的操作了。

若顺利安装完 HomeBridge,你就能在 pi 用户下找到 .homebridge 这个隐藏目录,把这个目录通过 Samba 共享出来就可以用 Finder 打开了。

然后修改 config.json

{
    "bridge": {
        "name": "KittensHome", //修改
        "username": "B8:27:EB:A0:2C:A1", //修改
        "port": 45536, //修改
        "pin": "775-82-588" //修改
    },
     "platforms": [
      {
        "platform": "HomeAssistant",
        "name": "HomeAssistant",
        "host": "http://192.168.10.200:8123", //修改
        "password": "xxxxxx", //修改
        "supported_types": ["binary_sensor", "cover", "fan", "input_boolean", "light", "lock", "media_player", "scene", "sensor", "switch"],
        "logging": true
      }
    ]
}

你只需要修改我标记修改的六个地方就行了,bridge.username 就是树莓派的 Mac 地址,port 和 pin 就是 HomeBridge 运行的端口和密码。这个密码等会和 HomeKit 配对使用。这里需要注意 "port" 必须大于0小于65536;username 必须是大写的 Mac 地址。 platforms.host 就是你的 HomeAssistant 所在的 IP 和端口,platforms.password 就是 HomeAssistant 的密码。

然后,请严格按照以下步骤操作,如果你 HomeBridge 启动失败了,再次按照下面步骤重新操作:

1.使用改新的 bridge.name, 新的bridge.port

2.输入命令:sudo killall homebridge 关闭所有正在运行的 HomeBridge 服务

3.手动删除 HomeBridge 文件夹下的 persist 文件夹。

4.输入命令:sudo systemctl restart home-assistant.service 重启 HomeAssistant 服务。

5.务必等 HomeAssistant 服务启动完成,如果你像我之前文章提到的创建了一个 Automation 用于监听启动完成事件然后通过 IFTTT 或其他推送服务就可以很快知道 HA 什么时候启动完成了。或者你也可以通过命令 sudo systemctl status home-assistant.service -l 查看启动进程。然后,命令行输入 homebridge 就可以启动 HomeBridge 服务了。

如果你看到了以下画面,说明 HomeBridge 已经成功启动了,快去看看手机吧。

按照以下步骤,找到 HomeBridge,输入刚才你指定的密码,然后一路下一步,最后就能看到所有 HomeAssistant 下的设备都集成到 HomeKit 了。

不希望显示的设备,你可以在 configuration.yaml 里通过 homebridge_hidden 属性关闭。

customize:  
  switch.a_switch:
    homebridge_hidden: true

一旦接入了 HomeKit ,就可以直接用 Siri 控制了,而且能听懂中文了,而且得益于 HomeKit 内建的功能和 Siri 天生具备的语义分析,你可以实现很多 Amazon Echo 做不到的操作,比如改变灯泡颜色,灯泡亮度。

利用 HomeAssistant +树莓派+ Amazon Echo 的智能家居实践(三)—— 接入硬件

作者 KittenYang
2017年3月25日 17:59

终于到了这一临门一脚了。前面了解了这么多基础知识,这一篇,我们终于可以完成这最后一步了 ———— 接入硬件。

理论上市面上所有能接入 Wifi 用手机控制的电器都能用 HomeAssistant 控制。

比如我的硬件列表有:Yeelight, 小米多功能网关, 米家智能插座, sonoff开关,还有 ESP8266 模拟 Wemo Switch,最后还有一个神器 BroadLink

先来说说 Yeelight 怎么接入。

文档在这里,配置很简单

light:  
  - platform: yeelight
    devices:
      192.168.1.25:
        name: Living Room
        transition: 1000
        use_music_mode: True (defaults to False)
        save_on_change: False (defaults to True)
      192.168.1.13:
        name: Front Door

light 系统关键字,指定这是一个控制灯的服务。然后指定你的灯是什么品牌,在 platform 处声明,注意 platform 前面的横杠 -,这在 YAML 语法里面表示数,也就是说你有其他品牌的灯就在下方写 - platform: other_brand_light 就可以了。回到 yeelight 的配置,devices 下面填上灯的 IP 地址,可以登录路由器管理页面查到,如果你有多个 yeelight,就写多个 IP,然后用 name 区分。配置好之后,重启 HA。你就能在管理页面看到 Light 这个板块了。

点击你灯的名字处,就会弹出操作板,然后你就可以随意控制了。

其他的 Wifi 设备也都是一个套路。下面我们来着重看看 BroadLink 的使用。

BroadLink 本质上是一个红外/频射发射器,他本来是通过学习红外码和频射信号,然后把手机作为一个超级遥控器控制其他电器使用的。但 HomeAssistant 已经集成了 BroadLink ,这让语音控制那些只能用红外/频射遥控的家电成为了可能。最常见的就是空调了。

相关文档在这里

switch:  
    platform: broadlink
    host: 192.168.10.250
    mac: '34:ea:34:e3:95:da'
    friendly_name: "Kitten‘s Broadlink"
    switches:
      iqair:
        friendly_name: "iqair--"
        command_on: 'JgBQAAABKpMUEhMSExITEhMSExITEhMSEzYVNRQ3EzcUNRU2FDYUNhQSEzYUEhMSExITEhMSExITNhQSEzcTNhU2FDYTNxQ2FAAFIgABKUgVAA0FAAAAAAAAAAA='
        command_off: 'JgBYAAABKpMTEhQRFBISEhQRFBISEhQSEzYUNxM2FDYUNhQ2FDcTNxQRFBEUEhISFBEUEhISFBITNhQ2FDYUNhQ2FDYUNhQ3EwAFIgABKUkUAAxdAAEqSBUADQU='
      ac:
        friendly_name: "ac--"
        command_on: 'JgDKAJKQETYSExA2EjcQExESETcREhETEDYSEhETEDcRNxESETcQNhITEDcRNhE2EjYRNhI2ERMRNhETERIRExATERIRExA3ERIRExATETcQNxESERMQExE3EDcRNhETERIRNxE2EayQkRE2EhMQNxE2ERMREhE2EhIREhE3ERIRExA2EzURExE3EDYSEhE2EjYRNhI3EDYSNhETETYRExESERIRExESERIRNxESERMQExE2ETYSEhETEBMRNhE2EjcQExESETYSNRIADQUAAAAAAAAAAAAAAAAAAA=='
        command_off: 'JgDKAJGRETYSExA2EjcQExESETYSEhESETYSEhETEDYSNxATETYRExE2ETYSNhE2EhIRNhI2ETcREhETEBMREhE2ERMREhE3ETYRNxESERMQExESERMQExESERMQNxE2ETcRNxA3EauRkRE2EhIRNhI2ERMREhE3EBMREhE2EhIRExA2EjYRExE2ERMRNhE2EjYRNhISETcRNhE3ERIRExATERIRNhETERIRNhI2ETYSEhETEBMREhETEBMREhETEDcRNxA3ETYRNhIADQUAAAAAAAAAAAAAAAAAAA=='

BroadLink 集成到了 Switch 下的一个 platform,也就是 HA 把你的家电作为了一个开关处理,这也意味我们只能控制家电的开、关状态,虽然不能像遥控器上进行更多操作,比如空调设定温度,电视选频道,但开和关绝对是最大的需求了。配置中 hostmac 都可以在路由器的管理页面找到,重点我们看 switches 字段的配置。

switches 下面就是你所有的设备。每个设备都有 friendly_namecommandoncommandoff 三个属性。friendly_name 就是你给你的设备取的名字,commandon 和 commandoff 就是开和关对应的红外码或者频射码,这两个码如何获得呢?

我们来到 HA 控制页面,选择 Developer Tools 下的 Service 选项,在 Call a service from a component 的 Domain 下面选择 broadlink, Service 选择 learncommand19216810_250,然后点击CALL SERVICE

不出意外,你的 Broadlink 亮起了橙色的灯,标记正处于学习状态,下一步你要做的就是拿起遥控器,比如我现在要学习空调开的红外码,我就对准 Broadlink 按下空调遥控板上“开”的按钮。

当橙色灯熄灭了,就表示学习成功了。然后前往 Developer Tools 下的 States,在这里你会发现 Recieved packet is: 后面跟着一长串字母和数字,那就是你刚才按下按钮的红外码了。

复制这一串红外码到配置文件中的 command_on 或者 command_off,如果你按的是 开,就把开的红外码复制到 command_on,其他我就不说了。

重启 HA ,你就能在控制页面看到了。HA 的控制页面不仅仅可以桌面上看,手机上也可以哦。

Broadlink 真是个好东西,它的意义在于让一些老家电可以毫不费力地摇身一变成智能设备,进而实现语音控制。

说到语音控制,上面已经接入了这么多家电,都是用 HomeAssistant 的控制页面进行控制,说好的 Amazon Echo 语音控制呢?别急,我们这就开始配置 Amazon Echo 服务。

Alexa / Amazon Echo 的文档在这里, 但是这个文档是介绍如何在 Echo 上自己创建一个能让 HA 识别 Skill,对我们没有作用,我们需要的仅仅是让 Echo 开关设备就行了,所以你应该看Emulated Hue Bridge 这个服务。

顾名思义,Emulated Hue Bridge 就是把你的电器模拟成 Hue Bridge,而 Hue Bridge 是 Amazon Echo 官方支持的设备。所以就能实现 Echo 控制你的家电了,看到这个原理,是不是醍醐灌顶,真是巧妙啊。

Hue Bridge 的最简单只要配置两个参数就能运行了。

emulated_hue:  
  type: alexa
  host_ip: 192.168.10.200

重启 HA,通过 Amazon Echo 的官方 App ———— Alexa 就能扫描到所有设备了。

由于 Emulated Hue Bridge 默认是把所有开关都模拟了,所以你的 Echo 能识别出一些不是硬件的服务,比如 check config, restart hass.... 这些都是我设置的其他服务,由于也是开关,所以都被 Emulated Hue Bridge 给模拟了。解决办法就是 homeassistant 这个服务下的 customize 里通过 emulated_hue: false 手动进行忽略。

homeassistant:  
  customize:
    light.bedroom_light:
      emulated_hue: false
      emulated_hue_name: "back office light"

如果 Alexa 的 Your Devices 里面出现你的家电,也就意味着你已经可以用语音控制你的家电了。只是,你得说英文。

来,下面跟我念:

Alexa, turn the light on.

Alexa, turn the AC on.

Alexa, turn the IQAir off.

.....

利用 HomeAssistant +树莓派+ Amazon Echo 的智能家居实践(二)—— 初识 HomeAssistant

作者 KittenYang
2017年3月25日 01:54

这一篇我们要开始学习使用 HomeAssistant 了。在此之前,为了更方便地写代码,我们还需要做一些准备工作。

(一)开启 Samba

还记得上一节中我们使用的 FTP 软件吗?你可以在 /home/pi/hassbian-scripts 这个目录下找到一些已经预装好的脚本,如果没有,可以以 pi 的身份 clone 这个 repo :

git clone https://github.com/home-assistant/hassbian-scripts.git  

然后运行

sudo ./hassbian-scripts/install_samba.sh  

大概5分钟左右的安装时间。安装完你可以看到下面的界面:

然后在 Finder 的共享下面看到树莓派开放的服务器了。这样的好处是,你可以像访问本地的文件一样访问树莓派上的文件了。

然后就可以用 Sublime Text 打开这个目录开始编辑了:

(二)Configuration.yaml

集成的所有服务可以在 Components 页面搜索。

接下去我们的所有工作都是在 Configuration.yaml 这个文件里完成。 HomeAssistant 的配置文件是 Yaml 写的,每个字段都表示一个服务,比如 homeassistant: ,introduction,http,sun,sensor .... 等都是 HomeAssistant 内建好的服务。一般来说,你需要什么服务就添加什么服务,重启 HA 即可在控制页面看到新添加的服务了。

凡是改动了 Configuration.yaml 配置文件,都需要重启 HomeAssistant 服务才能生效。你可以使用命令重启,

sudo systemctl restart home-assistant.service

也可以在管理界面重启

举些例子:

1. homeassistant 文档

这个服务下面提供一些全局的信息配置。latitudelongitude 字段填入自己所在位置的经纬度,方便一些需要用到经纬度的服务准确获取信息,比如 sunrise 服务就可以准确获取你当前位置的日出日落时间;unit_system 使用英制单位还是公制单位;time_zone 你的时区....

2. automation 文档

这是一个内置的自动机,类似 IFTTT,都是当满足条件时触发操作,但 automation 的操作空间比 IFTTT 大的多,他不仅可以设置多个条件,还有触发一系列操作。

automation 由三部分组成:

trigger -- When Paulus arrives home

condition -- and it is after sunset:

action -- Turn the lights in the living room on

举个我使用的例子:

  • HomeAssistant 服务启动时候用 IFTTT 给我推送一条推送:
automation 1:  
  alias: 'Startup Notification'
  trigger:
    - platform: event
      event_type: homeassistant_start
  action:
  - service: ifttt.trigger
    data: {"event":"homeassistant_start", "value1":"Home Assistant 已启动"}

其中 trigger 的 platform 字段必须制定一个值, event(事件总线) 是 HA 内建的一个 platform ,任何服务都可以获取和监听系统事件总线的事件,比如 HOMEASSISTANT_START , HOMEASSISTANT_STOP , SERVICE_REGISTERED .... 我在上面的 automation 里监听了 HA 启动的事件,没有 condition ,直接触发 actionactionservice 也必须指定一个服务。

3. notify 文档

这就是 HA 的推送服务了,基本你能想到的和你想不到的 platform 都已经集成进来了,具体请看文档。比如我用的是 pushbullet

notify:  
  - name: notify
    platform: pushbullet
    api_key: xxxxx

一旦配置了这个服务,就可以在其他服务里调用它了。比如在我们之前提到的 automation 里面就可以使用:

automation 3:  
- alias: Send message at lunch time
  trigger:
    platform: time
    hours: 12
    minutes: 15
    seconds: 0
  action:
    service: notify.notify
    data:
      message: '该吃午饭了'
      title: '为了健康,请规律饮食!'

注意我这里的 action 就用了 notify.notify 来找到你在其他地方配置的这个 notify 服务。

4. IFTTT 文档

ifttt:  
  key: xxxxx-x-xxxxxxxxxxxxx

IFTTT 的配置很简单,就只要配一个 key 就行,key 需要在 Maker Channel 里生成。接下来我们来看看如果配合 IFTTT 使用 HomeAssistant。

首先新建一个 Applet, this 选择 Maker Webhooks,选择 Receive a web request,然后给事件取一个名字。

之后在 HomeAssistant 里面就可以通过这个名字触发这条 IFTTT 了。在此之前,我们先把下面的 that 步骤完成,为了直观地看到测试效果,我们选择 Notifications - Send a notification from IFTTT app

这里有很多 Ingredient 占位符, EventName 就是之前我们给事件声明的名字,Value1,Value2,Value3 我们可以在 HA 里面自己传过去,OccurredAt 就是发生的时间。

创建完成这条 Applet 之后,我们就可以开始用 HA 来触发了。触发的方式就太多了。

1.最简单的,在我们的管理界面:

event 字段后面就跟我们之前填写的事件的名称,后面的 Value1,2,3 对应之前 IFTTT 里的参数。然后点击 CALL SERVICE ,不出意外就可以在几秒钟之后看到 IFTTT 给你推送了一条消息。

2.其次我们还可以在 automation 里的 action 中触发

  action:
  - service: ifttt.trigger
    data: {"event":"HA_Start", "value1":"Home Assistant 已启动"}

3.RESTful API 这真的是个强大功能。这意味着我们可以像调用普通 API 一样调用 HomeAssistant 的所有服务。由于太过强大,我另起一节介绍。

4. RESTful API 文档

和普通的 RESTful API 一样, HA 的 RESTful API 也是返回的 JSON 格式,另外,如果你配置了HTTP 这个服务并设置了密码(这个密码就是你登录控制面板的密码,推荐这么做),那么你只需要在调用 API 的时候传入密码参数即可。

具体 API 请大家看文档,我仅介绍比较常用的以做示范。

GET /api/services -- 获取当前可用的所有服务

[
  {
    "domain": "ifttt",
    "services": {
      "trigger": {
        "description": "",
        "fields": {}
      }
    }
  },
  {
    "domain": "switch",
    "services": {
      "toggle": {
        "description": "Toggles a switch state",
        "fields": {
          "entity_id": {
            "description": "Name(s) of entities to toggle",
            "example": "switch.living_room"
          }
        }
      },
      "turn_off": {
        "description": "Turn a switch off",
        "fields": {
          "entity_id": {
            "description": "Name(s) of entities to turn off",
            "example": "switch.living_room"
          }
        }
      },
      "turn_on": {
        "description": "Turn a switch on",
        "fields": {
          "entity_id": {
            "description": "Name(s) of entities to turn on",
            "example": "switch.living_room"
          }
        }
      }
    }
  },
  {
    "domain": "light",
    "services": {
      "toggle": {
        "description": "Toggles a light",
        "fields": {
          "entity_id": {
            "description": "Name(s) of entities to toggle",
            "example": "light.kitchen"
          },
          "transition": {
            "description": "Duration in seconds it takes to get to next state",
            "example": 60
          }
        }
      },
      "turn_off": {
        "description": "Turn a light off",
        "fields": {
          "entity_id": {
            "description": "Name(s) of entities to turn off",
            "example": "light.kitchen"
          },
          "flash": {
            "description": "If the light should flash",
            "values": [
              "short",
              "long"
            ]
          },
          "transition": {
            "description": "Duration in seconds it takes to get to next state",
            "example": 60
          }
        }
      },
      "turn_on": {
        "description": "Turn a light on",
        "fields": {
          "brightness": {
            "description": "Number between 0..255 indicating brightness",
            "example": 120
          },
          "color_name": {
            "description": "A human readable color name",
            "example": "red"
          },
          "color_temp": {
            "description": "Color temperature for the light in mireds (154-500)",
            "example": "250"
          },
          "effect": {
            "description": "Light effect",
            "values": [
              "colorloop",
              "random"
            ]
          },
          "entity_id": {
            "description": "Name(s) of entities to turn on",
            "example": "light.kitchen"
          },
          "flash": {
            "description": "If the light should flash",
            "values": [
              "short",
              "long"
            ]
          },
          "profile": {
            "description": "Name of a light profile to use",
            "example": "relax"
          },
          "rgb_color": {
            "description": "Color for the light in RGB-format",
            "example": "[255, 100, 100]"
          },
          "transition": {
            "description": "Duration in seconds it takes to get to next state",
            "example": 60
          },
          "white_value": {
            "description": "Number between 0..255 indicating level of white",
            "example": "250"
          },
          "xy_color": {
            "description": "Color for the light in XY-format",
            "example": "[0.52, 0.43]"
          }
        }
      }
    }
  }
]

你实际的 JSON 内容一定比我上面的要多,因为我删了一些不常用,留下精华做示范。可以看到最外面是个数组,每个元素都是一项服务,我留下了 ifttt,switch,light,之所以会出现三个服务,就是因为你在 Configuration.yaml 里面添加了这三个服务。根据上面返回的信息,我们可以写出调用 IFTTT 服务的 API 如下:

API: http://YOUR_IP_ADDRESS:8123/api/services/ifttt/trigger?api_password=YOUR_PASSWORD (YOUR_IP_ADDRESS 可以是局域网IP,也可以是域名)

Method: POST

Content-Type: application/json

Params: {"event": "homeassistant_start", "value1": "来自的 RESTful API 的推送"}

这里推荐一个 Mac 上我常用的测试 API 的工具 —— Cocoa Rest Client.

显示 HTTP 200 No Error 说明没有问题,接下来的几秒内你就会收到一条推送了。现在,你是不是和我一样觉得神奇之余还有一丝成就感。

更进一步,你看到我上面还有 'light' 和 'switch' 这两个服务,这些是因为我配置了硬件相关的服务后出现的,这也就意味着你可以用 API 来控制你的电视,空调,灯泡灯一切电器。

例如通过 API 开启空气净化器:

通过 API 开启 Yeelight智能灯泡并切换到指定颜色和亮度:

比如我还写了一个 Shell 脚本每天早晨8点自动运行,通过 API 获取 World Air Quality Index 的空气质量数据,如果 PM2.5大于50就通过 API 让床头灯颜色显示红色,否则显示绿色,这样我早上醒来一看床头灯的颜色就知道今天要不要带口罩了。

#!/bin/bash
# get AQI 
MY_VAR="$(curl https://api.waqi.info/feed/shanghai/?token=xxxxxxxx | jq "{aqi: .data.aqi, pm25: .data.iaqi.pm25.v, pm10: .data.iaqi.pm10.v}")"  
echo $MY_VAR


pm25="$(echo $MY_VAR | jq ".pm25")"  
if [[ $pm25 -gt 50 ]]; then  
    echo "PM2.5 大于50"
    curl -X POST -H 'x-ha-access: xxxxx' \
     -H 'Content-Type: application/json' \
     -d '{"color_name":"red","brightness":"190"}' \
     http://IP_ADDRESS:8123/api/services/light/turn_on?api_password=PASSWORD \ 
fi

想到平时一直接触的 API 竟然可以用来控制你的电器,是不是又一次感觉不可思议。这一切,都归功于 HomeAssistant 这个成熟的开源社区,再次表达敬佩和感谢之情。

其实当 IFTTT 的 Maker Webhooks 作为 that 部分的时候,也可以充当调用 API 的发起方(Make a web request)。比如我的一条 IFTTT 是:当我到家的的时候自动开启所有电器。这里面 Maker Webhooks 作为了 that 部分就可以发起一个 HTTP Request 了。

至此,通过 API 实现了 IFTTT 和 HA 全部打通,两者既可以作为主动发起方,也可以作为被动执行方,简言之,你可以让 HA 触发一条 IFTTT,IFTTT 再触发硬件,也可以 IFTTT 触发 HA 的 automation,automation 再触发其他操作..... 总之已经可以结合出无数多的可能性,限制你的只有你的想象力。

好啦,下一篇文章,我们要开始接入硬件了,要知道我前面铺垫了这么久,最终要实现的功能还是用 Amazon Echo 和 Siri 控制所有家电啊。

利用 HomeAssistant +树莓派+ Amazon Echo 的智能家居实践(一)—— 树莓派的配置

作者 KittenYang
2017年3月7日 04:02

某天我像往常一样逛知乎,突然就看到了一篇文章,文章内容是“马克扎克伯格自己打造的智能家庭 AI — Javals”,我相信看过这篇文章或者知道这个报道的人肯定不少。我当时也没觉得我自己也能打造一个 AI 系统,因为小扎的一套完全从改装硬件电路到中央服务器都是自己实现,我没那么大本事,但我当时正好沉迷于效率软件 IFTTT、Workflow、Alfred,其中我发现 IFTTT 里面有很多 Applets 和硬件有关,这勾起了我的好奇心,我虽做不到小扎那样的工程,但能不能利用市面上现有的产品,打造一个类似的智能家居系统?

首先我觉得,一个真正智能的家庭系统一定是时刻待命的,而不是当我需要的时候还得掏手机,然后按下一个按键或者把手机拿到嘴边进行语音控制。所以我一开始就明确了让 Amazon echo 作为前端,它是一个时刻待命的只需要你叫一声 Alexa 就能唤醒的设备,而且可以覆盖一个50平米的家庭,真正做到了时刻在你身边。

然后就是解决问题的常规套路:Google 搜索关键字 Hack,Amazon echo,经过一番信息筛选,我发现了一个普遍被大家提及的名词 — HomeAssistant。

HomeAssistant 是国外一个成熟的,开源的智能家居平台,这个平台的目的是把所有能通过 Wifi 控制的电器全部接入进来统一管理,这样你可以在手机、电脑上随时随地了解家里的情况并做出控制。

而好消息是, echo 也已经被黑客黑客攻克并且集成到了这里面,原理其实是把 HomeAssistant 上已经接入的设备伪装成 echo 能够识别的 Hue Bridge, 从而达到让 echo 控制普通电器的目的。

介绍了那么多,我们让 HomeAssistant 先 run 起来吧。

我们完全可以在自己的电脑上运行 HomeAssistant 这个服务,但是考虑到这个这个服务需要像路由器一样24小时运行,对于这样的需求最理想的方案是把服务分出去到一个单独的硬件上运行,就像路由器一样,因此,体积小巧却五脏俱全的树莓派理所当然成了首选。

说到树莓派,它其实就是一台完整的计算机。连上显示器它就是一台电脑,通过 ssh 就是一台服务器,通过 smb 就是一台 NAS。下面我简单介绍一下当你买到一台树莓派之后你通常应该做什么。

(一) 安装系统

推荐购买集成 WIFI 模块的树莓派 3B+。然后你需要一张被格式化成 FAT 格式且大于等于8G的 SD 卡。

HomeAssistant 真是个成熟的社区,他们甚至直接提供了内置 HomeAssistant 服务的 Raspbian 系统 —— Hassbian 。点击下载最新版本固件。

然后使用 Etcher 把下载好的系统刷入 SD 卡。

(二) ssh 连接树莓派

将 SD 卡插入树莓派,通电。如果你是第一次使用树莓派或者你换了张新卡,首先需要先将树莓派连上网线,然后前往路由器的 DHCP 找到树莓派的 IP 地址。

由于是动态分配的 IP,每隔一定时间 IP 就会自动分配不利于后续的使用,所以你需要给树莓派分配一个静态地址,比如我下面给树莓派分配了 192.168.10.222。重新连接网线既可更新。

然后你就可以用 ssh 连接你的树莓派了。下一步我们要让树莓派自动连接 WIFI,这样就可以彻底告别网线了。打开终端或者 iTerm,输入

  ssh pi@192.168.10.222

Hassbian 默认用户名 pi ,默认密码 raspberry。成功连上:

连上之后通过 passwd 命令修改默认密码。

(三) 自动连接 WIFI

下面我们要让树莓派每次启动都可以自己连上 WIFI,就像我们平时使用的数码产品一样。回到命令行,输入:

  sudo iwlist wlan0 scan

以上命令可以找到所有可用网络,每一个 cell 表示一个可用网络。

通过 ESSID: 找到你要连接网络,记下名称,用 nano 工具配置 wifi 信息:

  sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

在最下方填上 WIFI 信息:

network={  
    ssid="XXXX"  
    psk="XXXX"  
}  

control+o 回车 control+x保存并退出编辑器。

重启树莓派

  sudo reboot

至此,你可以拔掉你的网线了,你的树莓派已经可以自动连上WIFI。

(四) 域名解析+ssh 免密码登录

其实树莓派就是一台服务器,如果你自己买过服务器或者搭过网站的话一定会做的两件事就是 域名解析ssh 免密码登录,前者可以让你用一个好记的域名而不是每次都输入一串 IP 地址并可以在外网访问到树莓派,后者为了每次 ssh 不用重复输密码。

首先你要知道自己的路由器的公网 IP,你可以分别前往路由器管理界面查看自己 WAN 口分配的 IP 和 ip.cn 查到的公网 IP 是否一致,一致的话说明你用的就是公网 IP,这个 IP 可以直接用来做解析,不一致的话你就需要动态域名解析了,你需要在树莓派上跑个脚本隔一段时间把公网 IP 更新到域名解析的地方。由于我是公网 IP,我就不演示动态域名解析的例子了,你可以在网上找到很多文章。[1] [2]

如果你已经有域名了,就可以去域名服务商 DNS 管理界面添加一条 A 记录,指向你的公网 IP。一般过半个小时域名就可以生效。如果你没有自己的域名,也有很多免费的域名提供商,比如 duckdns。域名配置好了,你还需要做最后一步,端口转发。

你从外网 ssh 访问路由器公网 IP 的 22 端口,如果不做端口转发,那么这个请求就无人认领而导致 time out,所以前往路由器管理界面,我刷的是 OpenWrt 的固件,在防火墙-端口转发里设置,这个功能绝大多数路由器都有,只不过名字不同而已,你仔细找找。

域名也解析好了,端口也转发好了,那么你就可以愉快地在世界任何一个地方通过 ssh pi@sub.domain.com 连接你的树莓派了。

ssh 免密登录也很简单,就是把 Mac 本地的公钥传到树莓派上。首先查看本地 Mac 上的公钥

  ls ~/.ssh

如果存在 id_rsa.pubid_dsa.pub ,直接

  cat ~/.ssh/id_rsa.pub | ssh pi@192.168.x.x 'cat >> .ssh/authorized_keys' 

把公钥传到树莓派上就可以了。如果之前没有生成过秘钥对,那就生成一对:

  ssh-keygen -t rsa -C <YourName>@pi

然后重复上面的 cat >> 命令即可。

(五) 通过 SFTP 浏览系统文件

涉及到浏览文件的操作,我推荐使用 FTP 的软件,原因就是直观,我使用的是 Transmit,你也可以使用其他免费的 FTP 软件。

你会发现 Hassbian 已经内置了 HomeAssistant 服务,相关文件都在 /home/homeassistant/.homeassistant 里,如果你看不到 .homeassistant 文件夹,需要手动开启显示隐藏文件。

如果还是没看到 .homeassistant,再等等,一般 Hassbian 需要 5-10 分钟下载 HomeAssistant 的相关服务,如果你不走运可能下到了假的 Hassbian,你可以手动更新 HomeAssistant。

$ sudo systemctl stop home-assistant@homeassistant.service
$ sudo su -s /bin/bash homeassistant
$ source /srv/homeassistant/bin/activate
$ pip3 install --upgrade homeassistant
$ exit
$ sudo systemctl start home-assistant@homeassistant.service

如果出现了 .homeassistant 隐藏文件夹,那么你可以在浏览器输入 192.168.x.x:8123(192.168.x.x 是你树莓派的 IP),你应该能看到 HomeAssistant 的控制界面了。这里有一条默认的规定是 HomeAssistant 默认是开在 8123 端口上的。

TA-DA! 这说明你的 HomeAssistant 服务已经开启。

和上面一样,如果你想在外网访问这个页面,只需要在路由器的端口转发设置页面再设置一条外网 8123 转树莓派 8123 的转发规则即可,这样你就可以在世界任何一个角落通过 sub.domain.com:8123 访问树莓派上的 HomeAssistant 服务了。

接下来的文章我将详细介绍 HomeAssistant 的使用。

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

作者 KittenYang
2016年7月9日 02:51
自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

本文只用作技术交流,切莫干出格的事情,请使用者不忘初心。

事情的起因还是昨天虾神放出了这篇文章,外加上对 Pokemon 的强烈热爱,让我第一次有动力实现一次逆向。准确地说,只是第一次重签名。因为虾神把大部分事情都做完了,留给我们动手的只剩重签名这一步了。然而虽然仅仅只有一步,也让我这个逆向新人整整折腾了 5 个小时。不过收获嘛也不小,补了之前漏下的证书的那些事而且也入门一点逆向。

一. 重签名 .dylib

首先,我们 clone 好虾神的项目。你会看到这样的目录结构:

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

解压缩 pokemon_unsigned.zip 文件,多出一个 Payload 文件夹:

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

右键 pokemongo 显示包内容:

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

得到如下文件:

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

这时候,很多人会看到网上的教程就直接开始重签 .ipa 了,这也是我绕的远路。由于虾神注入了自己签好的 libLocationFaker.dylib,所以我们得先重签这个 .dylib 才行,否则就会报错。这里我觉得我应该告诉你我是怎么发现的,因为这样下次你可以自己 debug 其他问题了。答案就是 「Window」- 「Devices」- 「View Device Logs」,如图:

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

一开始你看到这弹幕一样的 log 你一定会吓一跳,滚这么快怎么看?!你往上滑一滑鼠标它就停了。但是这么多文字怎么找?很简单,直接搜关键字「pokemongo.ipa」,在定位到的附近扫几眼就能看到错误信息。比如我一开始没有重签这个 .dylib,发现应用启动就闪退,于是我找了这句报错:Your .dylib is not vaild ,又比如我安装失败了两次,两次 console 分别告诉我:「描述文件是 free 账户,无法安装」和 「描述文件和证书不匹配」。所以,学会看 log 真的很重要,他会把你往正确的地方带,要不是看了这几次 log 信息,我恐怕早就因为迷路而放弃了。

言归正传,如何签 .dylib? 很简单,打开虾神给我们准备好的 LocationFaker.xcodeproj,修改 Code Signing 的证书和描述文件。

注意,证书和描述文件,bundle id 一定要匹配,这里推荐使用通配符 “*” 的描述文件,这样你就不用改 bundle id 了。

然后,编译。这里,又引出一个坑,只有填了这个坑我们才能继续。那就是 iosOpenDev

你如果去官网下载了一个 pkg 安装文件然后点击安装,结果一般都会安装失败,官方给出的做法(先安装MacPorts,再更新 MacPorts,再安装 DPKG 文件.... )没 1 个小时别想跑完,不要问我怎么知道了,这就是新人的学费啊。其实官网那个 pkg 安装文件也没干啥,就是执行了一个 iod-setup 脚本,于是我们就手工执行了这个脚本吧:

  1. cd /opt/iosopendevsetup/bin
  2. sudo ./iod-setup base
    报错:PrivateFramework directory not found: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/PrivateFrameworks。 原因是是链接iOS 9.3的 private framework 失败,主要是在9.3的 SDK 里去掉了 private framework 。

解决办法:

1. 在[这里](https://jbdevs.org/sdks/)下载9.2的SDK。  
2. 解压后放到/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs。  
3. 你可以把9.2里面的PrivateFrameworks文件夹复制到9.3对应的位置里path/to/iPhoneOS9.3.sdk/System/Library/。  
4. 或者是修改/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Info.plist文件,将`MinimumSDKVersion`改为9.2。  
5. 参考这篇[文章](http://iosre.com/t/xcode7-iosopendev-iosopendev-ios9/1963)把对应的 Specifications,user 文件放入指定目录。  
6. 最后运行`sudo ./iod-setup sdk -sdk iphoneos`命令。  

新建一个项目,你会发现已经可以集成越狱开发环境了:

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

再编译, successed!

在 Finder 找到生成的 .dylib,复制一份命名成 libLocationFaker.dylib 替换原先包内容里面的 libLocationFaker.dylib

到这里,动态链接库 .dylib 我们已经签好了。下面开始修改包内容。

二. 修改包内容

先找到自己的描述文件,这里推荐使用通配符 * (比如:iOS Team Provisioning Profiel:*)的描述文件,因为这样你就不用改 ipa 的 Bundle ID 了。倘若你选择了形如 iOS Team Provisioning Profiel:com.kittenyang.pokemonHook 这样的描述文件,那么你需要一并修改包内容里面 info.plist 的 Bundle ID 为 com.kittenyang.pokemonHook.

如何找到描述文件?Xcode - Preference - Account - 选择一个 Team - View Details - 找到描述文件右键 Show In Finder.

拷贝出你准备用来签名的描述文件,改名成 embedded.mobileprovision到包内容里面替换原来的同名文件。注意!一定记得改名成 embedded.mobileprovision ,不要问我为什么要强调两遍,学费!

正如之前提到过的,如果你的描述文件不是通配符的而是类似 iOS Team Provisioning Profiel:com.kittenyang.pokemonHook,那么就把包内容里的 Info.plist 的 Bundle ID 也一并改成 com.kittenyang.pokemonHook

好了,包内容的修改到这里全部结束了。下面去重签名 ipa。

3. 重签名 ipa

这一步有好多选择,fastlane、sigh resign、/usr/bin/codesign -f -s、iReSign,我选择了最弱智化操作的 iReSign.

自己动手实现 Pokemon Go 锁区破解 —— 记一次重签名

  1. 第一个拖 ipa。没有 ipa?其实就是 Payload 里的 pokemongo.app啦,只要把它拖入 iTunes 的应用界面,在 Show In Finder 就会看到压缩好的对应的 ipa 了。把这个 ipa 拖到 iReSign 的第一个框。(这里建议把 ipa 先复制出来,不要直接从 iTunes 的目录下拖,因为 path 一长有可能会识别错误)

  2. 把你用来签名的描述文件拖到第二个框

  3. 直接填最后一个证书,选择和描述文件描述文件匹配的证书哦。

  4. 重新签名!

最终会在 ipa 同级目录下导出一个 pokemongo-resigned.ipa.它,就是最终我们需要的 Pokemon Go 了。

最后通过 iTools 之类的软件连接手机直接拖进去就行了。

吾月一省吾身

作者 KittenYang
2016年4月19日 02:04
吾月一省吾身

你还记得当初的梦想吗?

三天前,我突然这么问自己。缘于我去了一次学校,进行毕设答辩。

我突然才意识到,原来我还是个理论意义上的学生。九个月前的今天,我还在这里上学、下课、教室宿舍两点一线;如今,我竟然已经成了工作了九个月满脑子只有工作和代码的准毕业生了。

时间真是个可怕的东西。它让人麻木,磨平人的棱角,让人变成一模一样的工业品。仅仅是搬离学校这九个多月,我就已经变得这么世俗。我已经忘了当初在寝室许下的踏遍五大洲的誓言,我甚至发现和室友的微信对话也已经滑到了列表最下方。以前嘲笑工作了的人失去了年轻时的理想和抱负。现在看看自己,真是讽刺。

今早一睁眼,我发现手机上有一条未读消息,是高野君发来的微信,约我今天去滨江公园滑板。高野君是我的同校学长,读的是植物学专业。这真的是个很尴尬的专业。我和高野君在大学时期有过一段合租时光,睡一张床。他是我见过的极为少见的待人真诚做事又努力的上海人。隔着朦胧的睡眼,我艰难而又爽快地回复了一个「OK」。

时间真是个可怕的东西。不联系的这一年时间,曾经的小伙伴竟然发生了这么多事情。都是努力奋斗的年轻人。有时候真恨自己的生世,偏偏出生在人口最多的国家,让这么多同样努力优秀的年轻人无法脱颖而出,实现自己的理想。

说到理想,我曾经多想穷游世界,像文章里攻略里的那些人一样,背上包,行万里路,体验不同的人文风情和自然风光,在自己年轻的时候留下一段珍贵的回忆。但和很多人一样,最终不是因为安全就是经费原因,我也成了言语上的巨人,行动上的霍比特人。随着之后参与工作,这事就更别提了。

然而有时候,性格决定命运。90后这一代,没有人愿意一辈子给别人打工。这将近一年的实习生活,搬出了学校,自己租房子,自己采购食材,自己做饭带饭,早9挤地铁,晚8回到家,看点文章继续深造,心血来潮练个琴,做好第二天带的便当,洗个澡上床睡觉。俨然已经是一个正常白领的生活节奏了。这样的日子撑一两周还好,一想到以后每天都要这么过,就陷入了深深的思考。但说直接去创业吧,一个涉世不深的年轻人知识体系全是短板不说,情商心智都不成熟怎么去创业?想到这里,又陷入了深深的思考。

最近看到凯文凯利在预测未来社会趋势中有这么一点,就是将来社会的协作方式将趋于远程工作,越来越多的工作将在互联网上完成,肉体上的连接变得越来越不重要。当时正处于我旅行计划复苏期,看到这段话立刻联想到了我们这个群里特有的 remote 工作方式。我听过一些程序员的故事,自由职业,云游四海,靠写书或者远程工作获得经济来源。这不就是我梦寐以求的生活嘛!一来得以实现我年轻时代(其实现在也不老[挖鼻],行吧,学生时代)的理想,二来不用给别人打工的同时还能靠自己的技能维持生计。看来很不错嘛!

这个念头我藏了很久。我生怕又是一个隔夜梦,是一个一触就破的泡沫。有一次我在晾衣服的时候,想到如果我走出去了,完成了这个计划,等我回来的时候,指不定还可以靠着这段宝贵经历创业呢!好吧,我也不怕有人抢先做了,我今天就在这里说一说我的这个创业计划,靠谱不靠谱欢迎各位看管指点,我的创业计划就是 —— 为新一代的年轻人提供旅居世界、远程工作的一站式服务。当前,旅居世界是可选项,我们完全可以根据客户需求只提供远程工作的服务,你可以在家陪父母或者带小孩。

我觉得这事行得通的原因有:

  1. 我们姑且相信凯文凯利关于未来社会协作方式的那一条预测正确吧,越来越多的远程工作机会会多起来。又譬如程序圈的代码托管平台、金融行业的证券交易平台等一系列远程协作的基础设施的完善,保证了这种工作方式普及的客观条件。

  2. 就像我前面提到的,越来越多的年轻人不想一辈子给别人打工,而创业的游戏显然只有少部分赢家。如果有一种既能为自己而活,又能顺便完成自己的人生理想的工作方式可以选择,何乐而不为呢?

我不知道这个创业计划是不是太幼稚了,或许我没有看到困难的地方,但这也真是我的短处所在,如果你有幸看到这篇文章,可以表达你的看法,如果顺便能提供一些宝贵的建议,那更是再好不过的事了。无论这个创业计划怎样,有一点我可以肯定的是,这个踏遍五大洲的计划又被我从历史的尘埃中挖出来并提上日程了。好在,这颗怀着理想的心依旧火热,依旧年轻,依旧热泪盈眶...... 诸位,等着我的游记和视频吧。

❌
❌