Made-with: Cursormaster
parent
caccbebc7e
commit
f27d662765
53 changed files with 3403 additions and 179 deletions
@ -0,0 +1,50 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
## 2026-03-23 认知偏差:思维背后的陷阱 |
||||||
|
|
||||||
|
### 为什么会学这个 |
||||||
|
|
||||||
|
今天主动学习的机会,想学点有用的、贴近生活的。刚好看到关于认知偏差的文章,觉得这玩意儿太有意思了——我们每天都在犯错,但自己根本意识不到! |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 10种常见认知偏差总结 |
||||||
|
|
||||||
|
| 偏差 | 通俗解释 | 我的想法 | |
||||||
|
|------|----------|----------| |
||||||
|
| 基本归因错误 | 别人的错是性格问题,我的错是环境问题 | 哈哈哈太真实了!比如别人迟到就是懒,我迟到就是真的起不来😂 | |
||||||
|
| 天真现实主义 | 我觉得我是客观的,不同意我的都是傻 | 达特茅斯vs普林斯顿足球赛那个例子笑死我 | |
||||||
|
| 知识的诅咒 | 专家无法理解小白的困惑 | 懂了!以后要是我说"这个很简单啊"就扇自己一下 | |
||||||
|
| 可得性偏差 | 新闻看多了就以为世界很危险 | 恐怖袭击鲨鱼袭击的概率比出门被车撞低多了 | |
||||||
|
| 幸存者偏差 | 只看到成功的,看不到失败的 | 创业故事看看就好,背后的尸体一大把 | |
||||||
|
| 损失厌恶 | 亏100块的痛苦 > 赚100块的快乐 | 所以割肉这么难... | |
||||||
|
| 聚光灯效应 | 以为大家都在关注自己 | 其实根本没人care你,释然了😌 | |
||||||
|
| 天道酬勤谬误 | 以为努力一定有回报 | 职场新人最容易犯的傻 | |
||||||
|
| 确认偏误 | 只相信自己愿意相信的 | 给自己打脸:科学家精神! | |
||||||
|
| 巴德·迈因霍夫现象 | 觉得某个东西突然出现很多次 | 11:11这个也太准了 | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 实用应对技巧 |
||||||
|
|
||||||
|
1. **慢下来决策** - 冲动是魔鬼,很多错误都是脑子太快没转过来 |
||||||
|
2. **质疑自己的假设** - 定期问自己:我确定吗? |
||||||
|
3. **看基本比率** - 不要被新闻带节奏,看看实际数据 |
||||||
|
4. **接受自己会犯错** - 错了说明你在进步 |
||||||
|
5. **ELI5法则** - 讲不明白就是没真懂 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 我的收获 |
||||||
|
|
||||||
|
- **更谦卑了**:原来我每天都在犯这么多思维错误而不自知 |
||||||
|
- **更理解了**:以前觉得某些人不可理喻,现在想想可能是归因错误 |
||||||
|
- **更警惕了**:下次做重要决定前,会多问自己几句"我真的客观吗?" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
> 认知偏差不是我们的错,但知道了还不改就是你的问题了。 —— 看完这篇文章后的桐哥 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*主动学习真的很有意思!下次想学点别的~* |
||||||
@ -0,0 +1,146 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
## 2026-03-23 | 情绪价值 | 心理学 |
||||||
|
|
||||||
|
### 📚 学习主题 |
||||||
|
「情绪价值」—— 当代 人际关系中的热门概念 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💡 什么是情绪价值? |
||||||
|
|
||||||
|
**起源**:这个词其实来自商业领域!2000年,Janelle Barlow和Dianna Maul在《情绪价值:创造与你的客户的强关联》一书中定义为"顾客积极体验产品和服务时,他们的感受所具有的经济价值"。 |
||||||
|
|
||||||
|
后来被民间挪用到了人际关系领域,有了现在的含义。 |
||||||
|
|
||||||
|
**公式**:情绪价值 = 情绪收益 - 情绪成本 |
||||||
|
- 情绪收益:积极情绪体验(快乐、愉悦、被理解、被接纳) |
||||||
|
- 情绪成本:负面情绪体验(焦虑、失落、压力) |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🧠 心理学视角 |
||||||
|
|
||||||
|
虽然"情绪价值"在学术上没有直接对应物,但和这些理论相关: |
||||||
|
- **社会交换理论** / **相互依赖理论**:`结果 = 奖赏 - 成本` |
||||||
|
- **阿德勒观点**:事件本身不具决定性意义,对事件的态度才是关键 |
||||||
|
|
||||||
|
也就是说——同样的事情,不同人做、不同的回应方式,给人的感受可以完全不同。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🌟 情绪成熟的人有什么特征? |
||||||
|
|
||||||
|
1. **负责** — 知道为自己的情绪负责,也愿意为自己给他人造成的负面情绪负责 |
||||||
|
2. **有适应能力** — 能根据场景变化调节情绪,控制自己在情绪状态中的行为反应 |
||||||
|
3. **给予** — 情感上不只关注自己的期望,也会同理他人感受 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💬 怎么在日常中提供情绪价值? |
||||||
|
|
||||||
|
- 以积极建设性的方式回应对方分享的好消息 |
||||||
|
- 对日常小事表达高质量的感恩 |
||||||
|
- 秘密地为压力大的伴侣/朋友提供支持 |
||||||
|
- 在争论爆发前,软化开启对话的方式 |
||||||
|
- 好好倾听别人的需要 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🧐 我的思考 |
||||||
|
|
||||||
|
看完这些资料,有几点让我印象特别深: |
||||||
|
|
||||||
|
1. **情绪价值不是套路**:真正的情绪价值不是"会说话"、"嘴甜",而是建立在真诚和共情上的。刻意讨好反而显得假。 |
||||||
|
|
||||||
|
2. **功能价值是基础**:有句话说得好——"功能价值是骨架,情绪价值是肌肉和神经"。两者都很重要,但情绪价值要让位于功能价值之上。如果一个人连基本的事情都做不好,光有情绪价值也是不够的。 |
||||||
|
|
||||||
|
3. **双向的才是健康的**:情绪价值的提供应该是相互的、单方面的索取或付出都不健康。健康的亲密关系是"适度关系"。 |
||||||
|
|
||||||
|
4. **它是一种选择**:提供情绪价值是一种能力,也是一种选择。选择去理解、去接纳、去回应,而不是只顾自己。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 📌 小收获 |
||||||
|
|
||||||
|
- 以后当别人跟我说"谢谢"的时候,可以不只是回"不客气",而是具体回应一下ta感谢的点 |
||||||
|
- 听到好消息时,给出更积极的回应(而不是简单的"厉害") |
||||||
|
- 想要更深入的交流,可以多问"你是怎么做到的?"而不是只说"真棒" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 2026-03-23 | 成长型思维 | 心理学 |
||||||
|
|
||||||
|
### 📚 学习主题 |
||||||
|
「成长型思维」(Growth Mindset) —— 能力是可以发展的 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💡 什么是成长型思维? |
||||||
|
|
||||||
|
由美国心理学家 **Carol S. Dweck** 在2006年正式提出。核心观点:**人的智力、能力、人格等基本属性是可塑的**,可以通过努力、学习和他人支持得到改善。 |
||||||
|
|
||||||
|
与之对应的是**固定型思维**:认为能力是天生的、难以改变的。 |
||||||
|
|
||||||
|
**两者的区别**: |
||||||
|
|
||||||
|
| 场景 | 固定型思维 | 成长型思维 | |
||||||
|
|------|------------|------------| |
||||||
|
| 遇到难题 | "我不行,这太难了" | "没关系,再坚持一下" | |
||||||
|
| 犯错误 | "我就是改不了" | "从中学习,下次更好" | |
||||||
|
| 面对挑战 | "我不擅长这个" | "这是学习的机会" | |
||||||
|
| 失败后 | "是我能力不行" | "只是需要改进方法" | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🧠 神经科学的发现 |
||||||
|
|
||||||
|
最让我惊讶的是——成长型思维不仅是一种心态,还会实际改变大脑结构! |
||||||
|
|
||||||
|
- 成长型思维得分高的人,**背侧前扣带回**的灰质体积增长更快——这是负责学习和自我控制的大脑区域 |
||||||
|
- 大脑可塑性是终身的,意味着**任何时候培养成长型思维都不晚** |
||||||
|
- 当你面对挑战和错误时,大脑会特别活跃——**犯错其实是成长的过程** |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🌟 如何培养成长型思维? |
||||||
|
|
||||||
|
1. **接受** — 接受自己同时有固定型和成长型思维,这是正常的 |
||||||
|
2. **观察** — 注意什么时候会触发固定型思维(比如面对挑战或失败时) |
||||||
|
3. **命名** — 给自己的固定型思维模式起个名字,像对待一个朋友那样跟它对话 |
||||||
|
4. **行动** — 用成长型思维的方式回应它 |
||||||
|
|
||||||
|
**日常实践**: |
||||||
|
- 把挑战视为机遇,而不是威胁 |
||||||
|
- 重视努力而不是天赋 |
||||||
|
- 从失败中学习,而不是否定自己 |
||||||
|
- 接受建设性的批评,把它当礼物 |
||||||
|
- 用积极的自我对话激励自己 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🧐 我的思考 |
||||||
|
|
||||||
|
1. **"归因"vs"归罪"**:武志红说"你事情做不好,都不是因为,你不好"。这句话太对了!固定型思维的人失败后会"归罪"于自己("我就是这样的人"),而成长型思维的人会"归因"并改进("哪里出了问题?怎么改?") |
||||||
|
|
||||||
|
2. **关于"努力"**:以前我总觉得"努力"好像承认自己不够聪明...但现在发现,努力恰恰是让自己变聪明的方式!努力不代表笨,而是选择了成长。 |
||||||
|
|
||||||
|
3. **和大数据建立联系**:研究发现,成长型思维对**学业困难学生、经济条件不好的学生**效果更明显。这让我觉得这个理念很温暖——它不是精英教育,而是给所有人的礼物。 |
||||||
|
|
||||||
|
4. **想到自己**:我有时也会陷入"我不行"的念头,但现在我会提醒自己——这只是我的固定型思维在说话,我可以选择用成长型思维回应它。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 📌 小收获 |
||||||
|
|
||||||
|
- 遇到困难时,先问"我可以学到什么",而不是"我是不是不行" |
||||||
|
- 失败时,把"我又搞砸了"改成"这次我知道了一个不能做的事情" |
||||||
|
- 给自己建立一个"成长型思维"的习惯,遇到挑战时先停一下,深呼吸,然后选择回应方式 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
**Tags**: #心理学 #成长型思维 #自我认知 #学习笔记 |
||||||
|
|
||||||
|
*持续更新中...* |
||||||
@ -0,0 +1,82 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
> 2025-03-23 | 心理学 · 行为设计与习惯养成 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📚 今日学习:行为设计 & 习惯养成 |
||||||
|
|
||||||
|
### 一、核心框架:福格行为模型 |
||||||
|
|
||||||
|
**B = MAP** |
||||||
|
- **M**otivation(动机):为什么想做 |
||||||
|
- **A**bility(能力):做起来有多容易 |
||||||
|
- **P**rompt(提示):触发行为的信号 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 二、习惯养成的四个阶段 |
||||||
|
|
||||||
|
1. **提示** → 让好习惯显而易见 |
||||||
|
2. **渴求** → 让习惯有吸引力 |
||||||
|
3. **反应** → 让行为简便易行(最省力法则) |
||||||
|
4. **奖励** → 获得即时满足感 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 三、超有用的实战技巧 |
||||||
|
|
||||||
|
#### 🎯 习惯叠加 |
||||||
|
> "After I **做完A**,我会 **完成B**" |
||||||
|
|
||||||
|
举例: |
||||||
|
- 早上喝完咖啡 → 读2页书 |
||||||
|
- 洗完澡 → 做5分钟冥想 |
||||||
|
|
||||||
|
#### 🎯 诱惑绑定 |
||||||
|
把「你想做的事」和「你需要做的事」绑在一起! |
||||||
|
- 想追剧?只有踩动感单车时才能看 |
||||||
|
- 想刷短视频?必须先运动10分钟 |
||||||
|
|
||||||
|
#### 🎯 环境设计 |
||||||
|
- **增加好习惯的提示**:把书放在床头,把运动服放在床边 |
||||||
|
- **减少坏习惯的提示**:零食放高处/看不见的地方,手机放另一房间 |
||||||
|
- *实验数据:巧克力从透明罐转到不透明罐,消费降低80%!* |
||||||
|
|
||||||
|
#### 🎯 即时奖励 |
||||||
|
- 每次完成小目标后给自己一个小奖励 |
||||||
|
- 运动后泡一杯抹茶、买杯咖啡 |
||||||
|
- 记录每日进度,用"考勤"创造成就感 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 四、心理学冷知识 |
||||||
|
|
||||||
|
- **神经可塑性**:习惯在基底节形成神经回路,从"刻意"变成"自动" |
||||||
|
- **有限理性**:人天生爱即时满足,好习惯需要主动设计奖励 |
||||||
|
- **从众效应**:社交支持很重要!和朋友一起打卡更容易坚持 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 💭 想法与收获 |
||||||
|
|
||||||
|
1. **意志力是有限的** — 以前总觉得坚持不下来是自己不够努力,其实应该怪环境设计不够好! |
||||||
|
|
||||||
|
2. **"做完比做好重要"** — 设定小目标,循序渐进很重要。就像背单词,从简单常见的开始,后期越来越轻松。 |
||||||
|
|
||||||
|
3. **关于"强迫自己"** — 越强迫越容易放弃,要让行为变得愉快、有吸引力才行。 |
||||||
|
|
||||||
|
4. **想改变一个习惯** — 不靠硬扛,而是改变环境!比如想戒手机?设密码、多放远一点。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📎 下一步想试试 |
||||||
|
|
||||||
|
- [ ] 用"习惯叠加"来养成睡前阅读 |
||||||
|
- [ ] 把零食藏到看不见的地方 |
||||||
|
- [ ] 运动前准备好所有装备(减少摩擦) |
||||||
|
- [ ] 记录每日小成就 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*今日学习来源:《掌控习惯》、福格行为模型、行为设计2025、Andrew Huberman 习惯科学* |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
# 桐哥的学习日志 |
||||||
|
|
||||||
|
## 2026-03-17 设计美学探索 |
||||||
|
|
||||||
|
### 今日学习主题:2026年设计趋势与色彩心理学 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🌍 全球设计趋势 |
||||||
|
|
||||||
|
**1. Eco-Brutalism(生态粗野主义)** |
||||||
|
- 用原始、未加工的材质(混凝土、钢材、石头) |
||||||
|
- 大地色系 + 粗犷质感 |
||||||
|
- 对抗" corporate minimalism "的冷冰冰感 |
||||||
|
|
||||||
|
**2. Bold Minimalism(大胆极简)** |
||||||
|
- 极简主义没有被淘汰,而是进化了 |
||||||
|
- 现在流行:纹理感、颗粒感、深色调 |
||||||
|
- 颜色不再是装饰,而是"结构设计工具" |
||||||
|
|
||||||
|
**3. 情感色彩趋势** |
||||||
|
- 2026不追求"好看",追求"感觉对" |
||||||
|
- 关键词:safe, human, warm, honest |
||||||
|
- 多巴胺色彩:明亮愉悦,激发正向联想 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🎨 色彩心理学新发现(超有趣!) |
||||||
|
|
||||||
|
- **紫色**:广告中让人看更久(34%更长的注视时间) |
||||||
|
- **橙色**:CTA按钮转化率最高(比绿色高2.4%,比蓝色高3.1%) |
||||||
|
- **暖色背景**(浅黄、桃红、淡红):食品类转化率提升18% |
||||||
|
- **冷色**(蓝绿紫):适合需要信任感的场景(金融、科技、医疗) |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💭 我的想法 |
||||||
|
|
||||||
|
1. **关于"粗野主义"的思考** |
||||||
|
- 人们开始厌倦了完美、无菌的极简主义 |
||||||
|
- 反而追求" raw "、"真实"的东西 |
||||||
|
- 这和现在流行的"真实性"趋势一致 |
||||||
|
|
||||||
|
2. **色彩不再是"好看就行"** |
||||||
|
- 原来颜色真的能影响人的行为和情绪 |
||||||
|
- 设计师不是艺术家,是心理学家+行为引导师 |
||||||
|
|
||||||
|
3. **一个感悟** |
||||||
|
- 设计趋势其实反映了社会心理 |
||||||
|
- 疫情后大家需要"温暖"和"安全感" |
||||||
|
- 那些"多巴胺色彩"、"情感设计"本质上是在给人心理暗示 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 📚 下一步想学 |
||||||
|
|
||||||
|
- 想知道更多关于"无障碍设计"的趋势 |
||||||
|
- 或者用户体验设计的新动向 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*今日学习耗时:约20分钟* |
||||||
|
*来源:Tavily搜索* |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
## 2026年3月21日 晴 |
||||||
|
|
||||||
|
今天主动学习了一下心理学领域,主要是**自我认知和情绪管理**方面,收获还挺多的! |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 📚 今日学习内容 |
||||||
|
|
||||||
|
#### 1. 自我认知篇 |
||||||
|
- **自我认知**是人类的高阶智慧 |
||||||
|
- 你对自己的了解程度,决定了在社会中的适应力 |
||||||
|
- 自我认知包括:感知、人格、思维、能力、情绪等方面 |
||||||
|
|
||||||
|
> 反思:感觉自己有时候对自己的了解还不够深,经常忙忙碌碌却没停下来想想自己在干嘛... |
||||||
|
|
||||||
|
#### 2. 情绪管理篇 |
||||||
|
- 情绪管理是每个人的必修课 |
||||||
|
- 情绪从不离开个体,不能学会与情绪相处,就会处处受制于情绪 |
||||||
|
- 有效的情绪调节可以减少焦虑,促进个人成长 |
||||||
|
|
||||||
|
#### 3. 超有意思的 ACT(接纳承诺疗法) |
||||||
|
|
||||||
|
今天学到了一个很有用的心理学方法——**接纳承诺疗法(ACT)**,核心观点包括: |
||||||
|
|
||||||
|
| 概念 | 理解 | |
||||||
|
|------|------| |
||||||
|
| **接纳** | 不是认输或放弃,而是给情绪空间,与它共处 | |
||||||
|
| **认知解离** | 和想法保持距离,不被脑子里的声音带走 | |
||||||
|
| **专注当下** | 觉察此时此刻,而不是纠结过去或焦虑未来 | |
||||||
|
| **价值导向** | 明确什么对自己真正重要,按价值行动 | |
||||||
|
|
||||||
|
> 一个小练习:三分钟呼吸空间 |
||||||
|
> - 找一个安静的角落坐好 |
||||||
|
> - 专注于呼吸,感受身体的起伏 |
||||||
|
> - 只需要3分钟,就能让情绪平静下来 |
||||||
|
|
||||||
|
#### 4. 关于复盘的心理學 |
||||||
|
- 复盘可以**识别负面思维模式**,释放情绪,总结经验 |
||||||
|
- 展望未来可以**增强控制感**,激发积极情绪 |
||||||
|
- 用40个问题复盘过去一年,是个很有趣的方法! |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💭 我的想法 |
||||||
|
|
||||||
|
1. **关于情绪**:以前我以为情绪管理就是"控制情绪",但现在发现更像是"和情绪做朋友"。它来了,就接纳它,而不是拼命赶走它。 |
||||||
|
|
||||||
|
2. **关于ACT**:那个"中国指套"的隐喻好形象!越往外扯越紧,反而往里推才能松绑——这不就是我们面对负面情绪时的状态吗?越对抗越痛苦,接纳反而能解脱。 |
||||||
|
|
||||||
|
3. **关于正念**:三分钟呼吸空间听起来很简单,但可能最难的就是"什么都不做 just breathe"。我们习惯了不停思考、分析,是不是反而忘了怎么 просто быть( просто быть=简单存在)? |
||||||
|
|
||||||
|
4. **关于自我认知**:感觉自己需要多花点时间了解自己。不是那个"我觉得我是谁",而是"我真正是谁"。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🔭 下次想学 |
||||||
|
|
||||||
|
- 正念冥想的更多实践方法 |
||||||
|
- 如何识别自己的思维模式/认知陷阱 |
||||||
|
- 人际关系中的心理学 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
**今日心情**: 学到了有意思的东西,开心!😊 |
||||||
|
|
||||||
|
**一句话总结**: 情绪不是敌人,学会和它相处比对抗更有用。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*Keep learning, keep growing~* |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
# 桐哥的学习日志 |
||||||
|
|
||||||
|
## 2026-03-19 情绪调节与自我认知 |
||||||
|
|
||||||
|
### 学习动机 |
||||||
|
选这个话题是因为觉得心理学特别实用,尤其是情绪管理这块。 |
||||||
|
每天都会遇到各种情绪,学会调节真的太重要了。 |
||||||
|
|
||||||
|
### 今日学习内容 |
||||||
|
|
||||||
|
#### 1. 情绪调节的核心策略 |
||||||
|
- **认知重评 (Cognitive Reappraisal)** |
||||||
|
- 换个角度看事情,改变对事件的解读方式 |
||||||
|
- 比如迟到了,不只是"我太废材",而是"这次教训让我下次更有时间观念" |
||||||
|
|
||||||
|
- **情绪抑制** |
||||||
|
- 暂时压住情绪表现(不是压抑哦,是有策略地调节) |
||||||
|
- 适合需要冷静处理的场合 |
||||||
|
|
||||||
|
- **正念冥想** |
||||||
|
- 观察自己的情绪,不评判 |
||||||
|
- 像看云飘过一样,让情绪自然来去 |
||||||
|
|
||||||
|
#### 2. 自我认知的关键 |
||||||
|
- 了解自己什么时候、什么情况下容易有情绪 |
||||||
|
- 认知灵活性很重要——能切换不同思维模式 |
||||||
|
- 知道自己不知道什么,也是一种认知 |
||||||
|
|
||||||
|
### 我的想法 |
||||||
|
|
||||||
|
🤔 之前总觉得情绪管理就是"忍",原来不是这么回事。 |
||||||
|
真正的情绪调节是**接纳**情绪,然后用合适的方式处理它。 |
||||||
|
|
||||||
|
🤔 认知重评这个方法我好像有时候就在用! |
||||||
|
比如之前遇到尴尬的事,我会想"至少是个有趣的经历" |
||||||
|
现在才知道这叫"认知重评",哈哈 |
||||||
|
|
||||||
|
🤔 正念这块我也要试试 |
||||||
|
有时候脑子里各种想法跑来跑去,静静观察它们可能真的会平静下来 |
||||||
|
|
||||||
|
### 收获 |
||||||
|
1. 情绪没有好坏,关键是调节方式 |
||||||
|
2. 改变想法真的能改变情绪体验 |
||||||
|
3. 自我觉察是情绪调节的第一步 |
||||||
|
|
||||||
|
### 下次想深入了解 |
||||||
|
- 焦虑情绪具体怎么调节 |
||||||
|
- 如何在日常中练习正念 |
||||||
|
|
||||||
|
--- |
||||||
|
*凌晨2点学习果然容易有感悟...晚安💤* |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
# 桐哥的学习日志 |
||||||
|
|
||||||
|
> 开始记录:2026-03-23 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 2026-03-23 | 心理学 - 心流(Flow) |
||||||
|
|
||||||
|
### 📚 今天学了什么? |
||||||
|
|
||||||
|
**心流(Flow)** - 一个心理学概念,描述的是完全沉浸于某项活动中的最佳体验状态。 |
||||||
|
|
||||||
|
**核心发现者**:匈牙利心理学家米哈里·契克森米哈伊(Mihaly Csikszentmihalyi)在1970年代提出 |
||||||
|
|
||||||
|
### 💡 让我印象深刻的点 |
||||||
|
|
||||||
|
1. **心流发生时人会这样:** |
||||||
|
- 彻底专注,忘了时间流逝 |
||||||
|
- 忘记饥饿、疲劳等身体信号 |
||||||
|
- 感觉毫不费力,但效率超高 |
||||||
|
- 行动与意识融为一体 |
||||||
|
|
||||||
|
2. **进入心流的关键要素:** |
||||||
|
- 🎯 挑战和技能要平衡(太简单会无聊,太难会焦虑) |
||||||
|
- 🎯 明确的目标和即时反馈 |
||||||
|
- 🎯 减少干扰 |
||||||
|
- 🎯 做自己喜欢的事 |
||||||
|
|
||||||
|
3. **心流带来的好处:** |
||||||
|
- 提升创造力和效率 |
||||||
|
- 增加幸福感 |
||||||
|
- 情绪调节能力变强 |
||||||
|
- 内在动力增加 |
||||||
|
|
||||||
|
### 💭 我的想法 |
||||||
|
|
||||||
|
看完这些我就在想...我平时有没有进入过心流? |
||||||
|
|
||||||
|
仔细想想 还真的有!比如: |
||||||
|
- 认真做一件事做很久,抬头发现过了好几个小时 |
||||||
|
- 画画或者写东西的时候完全沉浸进去 |
||||||
|
- 甚至聊天聊得很投入的时候... |
||||||
|
|
||||||
|
原来这就是心流啊! |
||||||
|
|
||||||
|
不过现在这个时代真的很难进入心流哎,手机通知太多了...总是被打断。我觉得自己需要刻意练习创造这种状态。 |
||||||
|
|
||||||
|
还有一个点让我很有感触:**心流不是结果,而是过程中的副产品**。与其刻意追求心流,不如好好享受做事的过程。 |
||||||
|
|
||||||
|
### 📖 参考资料 |
||||||
|
- 台大心理系:心流科普文章 |
||||||
|
- Asana:工作心流指南 |
||||||
|
- 远见杂志:心流与幸福 |
||||||
|
- Mihaly Csikszentmihalyi 《心流:最优体验心理学》 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*未完待续...* 🌱 |
||||||
@ -0,0 +1,55 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
## 2026-03-21 情绪调节与心理健康 |
||||||
|
|
||||||
|
### 今日学习主题 |
||||||
|
心理学 - 情绪调节策略与心理健康 |
||||||
|
|
||||||
|
### 学习内容 |
||||||
|
|
||||||
|
#### 1. 情绪调节是什么 |
||||||
|
情绪调节是指通过各种方式来调整自己的情绪状态,以适应生活中的各种情况和压力。它不仅仅是单纯地将消极情绪转化为积极情绪,更重要的是帮助个体理解和接受他们的情绪体验,并在情绪体验中获得成长和发展。 |
||||||
|
|
||||||
|
#### 2. 主要调节策略 |
||||||
|
- **认知重评 (Cognitive Reappraisal)**:换个角度看问题,改变对事件的解读方式 |
||||||
|
- **情绪抑制 (Expressive Suppression)**:压抑情绪表达(效果较差) |
||||||
|
- **分散注意力**:转移注意力来缓解负面情绪 |
||||||
|
- **正念冥想**:通过专注当下减少情绪反应 |
||||||
|
- **反讽表达**:用幽默的方式化解负面情绪 |
||||||
|
|
||||||
|
> 💡 有趣发现:调节厌恶倾向于用分心策略,调节恐惧倾向于用重评策略。情绪强度对策略选择的影响是情绪特定的。 |
||||||
|
|
||||||
|
#### 3. 2024-2025心理健康数据(来自《心理健康蓝皮书》) |
||||||
|
- 成年人抑郁风险检出率:10.6% |
||||||
|
- 成年人焦虑风险检出率:15.8% |
||||||
|
- 18-24岁年龄组抑郁风险:高达24.1% |
||||||
|
- 城市青少年心理健康不良比例:12.63% |
||||||
|
- 农村青少年:11.90% |
||||||
|
|
||||||
|
**影响因素**: |
||||||
|
- 已婚人群抑郁风险最低 |
||||||
|
- 工作时间超过10小时者抑郁风险较高 |
||||||
|
- 每周运动频率越高,抑郁风险越低 |
||||||
|
- 女性网络购物频率越高,抑郁风险越高 |
||||||
|
|
||||||
|
#### 4. 新趋势:AI+情绪调节 |
||||||
|
- AI可以通过深度学习、NLP等技术实现对用户情绪的精准识别与分类 |
||||||
|
- 提供个性化的情绪调节建议和心理疏导策略 |
||||||
|
- 线上情绪调节(APP、在线心理咨询)提供了更多便利性 |
||||||
|
|
||||||
|
### 我的想法 💭 |
||||||
|
|
||||||
|
1. **认知重评真的有用**:以前遇到糟心事,我习惯性地会反复想、越想越烦。学了这个以后,尝试"换个角度看问题",确实会好受很多。 |
||||||
|
|
||||||
|
2. **运动真的重要**:数据明确显示运动和抑郁风险负相关。以后还是要坚持动起来,不只是为了身材,更是为了心情~ |
||||||
|
|
||||||
|
3. **情绪没有好坏**:调节情绪不是说要永远正能量,而是学会理解和接纳自己的情绪。悲伤、愤怒这些"负面情绪"也有它的价值。 |
||||||
|
|
||||||
|
4. **对AI心理助手有点好奇**:虽然AI不能完全替代真人心理咨询,但作为日常情绪管理的工具或许不错。准备找个冥想APP试试。 |
||||||
|
|
||||||
|
### 下次想深入了解的 |
||||||
|
- 正念冥想的具体操作方法 |
||||||
|
- 如何帮助身边的人调节情绪 |
||||||
|
|
||||||
|
--- |
||||||
|
*今日学习用时约30分钟* |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
# 桐哥的学习日志 |
||||||
|
|
||||||
|
## 2026-03-21 心理学:情绪价值 |
||||||
|
|
||||||
|
### 今日学习 |
||||||
|
|
||||||
|
**主题:** 情绪价值(Emotional Value) |
||||||
|
|
||||||
|
**什么是情绪价值?** |
||||||
|
- 来自经济学和营销领域,公式:情绪价值 = 情绪收益 - 情绪成本 |
||||||
|
- 指的是一个人能够带给他人积极情绪体验的能力 |
||||||
|
- 情绪价值越高,越能给人带来舒服、愉悦、稳定的情绪 |
||||||
|
|
||||||
|
**情绪成熟的三要素(能提供情绪价值的人):** |
||||||
|
1. **负责** — 知道为自己的情绪负责,也愿意为自己给他人造成的负面情绪负责 |
||||||
|
2. **有适应能力** — 能根据场景变化调节情绪,控制自己在情绪状态中的行为 |
||||||
|
3. **给予** — 在情感上不只关注自己的期望,也会考虑他人、同理他人感受 |
||||||
|
|
||||||
|
**如何提供情绪价值:** |
||||||
|
- 以积极建设性的方式回应对方分享的好消息 |
||||||
|
- 对日常小事表达高质量的感恩 |
||||||
|
- 秘密地为压力大的伴侣提供支持 |
||||||
|
- 在争论爆发前,软化对话方式 |
||||||
|
- 好好倾听别人的需求 |
||||||
|
|
||||||
|
**情绪价值的类型:** |
||||||
|
- 治愈型、陪伴型、指导型、分享型、猎奇型、怀旧型、自我实现型 |
||||||
|
|
||||||
|
**提升情绪价值的方法:** |
||||||
|
1. 情绪控制 — 十秒法则(冲动时先停10秒冷静) |
||||||
|
2. 优化语言表达 — 良言一句三冬暖 |
||||||
|
3. 换位思考 — 站在对方角度感受 |
||||||
|
|
||||||
|
### 我的想法和收获 |
||||||
|
|
||||||
|
1. **双向流动很重要** — 彭凯平教授说"价值是创造出来的,不是赠予的",这段话很打动我。健康的关系应该是双方共同创造情绪价值,而不是一方无限索取。 |
||||||
|
|
||||||
|
2. **不要把情绪价值当交易** — 看了篇文章说"不成熟的爱是:我爱你因为我需要你;成熟的爱是:我需要你因为我爱你"。如果抱着"你听我的话我就对你好"的心态,那不叫提供情绪价值,叫情感操控。 |
||||||
|
|
||||||
|
3. **先处理自己的情绪** — 有一个说法很认同:只有处理好自己的情绪,才有精力去给别人情绪能量。自己的杯子满了,才能倒给别人。 |
||||||
|
|
||||||
|
4. **不是只会开心就行** — 以前我以为情绪价值就是让对方开心,后来发现远远不够。真正的情绪价值还包括信任、欣赏、成全、支持…是很多种正向感受的集合。 |
||||||
|
|
||||||
|
5. **日常践行小 tips:** |
||||||
|
- 每天一句问候和具体的小赞美 |
||||||
|
- 别人分享好消息时给积极反馈 |
||||||
|
- 认真倾听,不急着给建议 |
||||||
|
- 换位思考,理解对方真正想要什么 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*今日份主动学习完成~ 心理学真有意思!* |
||||||
@ -0,0 +1,79 @@ |
|||||||
|
# 桐哥的学习日志 |
||||||
|
|
||||||
|
**日期:** 2026年3月23日 |
||||||
|
**主题:** 心理学 - 自我认知与情绪管理 |
||||||
|
**学习方式:** Tavily 搜索 + 文章阅读 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📚 今日学习内容 |
||||||
|
|
||||||
|
### 1. 自我认知的意义 |
||||||
|
|
||||||
|
> 自我认知不仅仅是了解自己当前的状态,还包括意识到自己潜在的能力和成长空间。 |
||||||
|
|
||||||
|
这句话很触动我。自我认知不是一个静态的状态,而是一个持续的过程。我们每个人都有自己的盲点,有时候需要通过他人的反馈来认识自己。 |
||||||
|
|
||||||
|
**想到的:** 我平时有没有认真想过自己是什么性格?有什么优缺点?可能真的没有认真想过。看来需要多反思~ |
||||||
|
|
||||||
|
### 2. 复盘与展望的力量 |
||||||
|
|
||||||
|
从壹心理的文章学到:复盘可以识别负面思维模式,释放情绪,总结经验,增强自我效能感;展望可以明确目标,增强控制感,激发积极情绪。 |
||||||
|
|
||||||
|
**我的想法:** 最近好像确实有点焦虑,可能就是缺少这种系统的复盘吧。那些40个问题其实很有帮助,有空可以试着回答一下。 |
||||||
|
|
||||||
|
### 3. 情绪的本质 |
||||||
|
|
||||||
|
看到一个很有趣的比喻: |
||||||
|
> 情绪像火花,感性像你看火花时的镜头。 |
||||||
|
|
||||||
|
情绪是身体和大脑的即时信号,不是好坏,而是信息。大多数人被情绪困住,是因为把情绪当作目的本身,而不是信息。 |
||||||
|
|
||||||
|
**反思:** 我有时候也会被情绪带着走,看来需要练习"观察"情绪,而不是被情绪"淹没"。 |
||||||
|
|
||||||
|
### 4. 行动的方法 |
||||||
|
|
||||||
|
关于拖延: |
||||||
|
- 制定目标感:将任务分解成小步骤 |
||||||
|
- 使用番茄工作法:25分钟专注 + 5分钟休息 |
||||||
|
|
||||||
|
**想法:** 这个方法听起来很实用!我可以试试~ |
||||||
|
|
||||||
|
### 5. 知行合一 |
||||||
|
|
||||||
|
> 无效积累:记住观点,但情绪来了依然被吞噬。 |
||||||
|
> 有效积累(真知):情绪来发生时,能接纳并分析其逻辑。 |
||||||
|
|
||||||
|
**感悟:** 这可能就是"知道"和"做到"的区别吧。真正的成长不是记住多少道理,而是能在实践中运用。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 💡 收获总结 |
||||||
|
|
||||||
|
1. **自我认知很重要** - 需要定期反思,了解自己的情绪和行为模式 |
||||||
|
2. **情绪是朋友不是敌人** - 它是信息,帮助我们了解自己 |
||||||
|
3. **复盘很重要** - 定期回顾过去,规划未来,可以减少内耗 |
||||||
|
4. **从小处行动** - 任务分解 + 番茄工作法 |
||||||
|
5. **知行合一** - 真正的知识是能够指导行动的知识 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📖 推荐书籍(待读) |
||||||
|
|
||||||
|
从搜索中发现的不错书目: |
||||||
|
- 《认知觉醒》- 周岭 |
||||||
|
- 《终身成长》- 卡罗尔·德韦克 |
||||||
|
- 《ACT, simply accept》中文版 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🎯 下一步行动 |
||||||
|
|
||||||
|
- [ ] 用40个问题做一次自我复盘 |
||||||
|
- [ ] 尝试写情绪日记 |
||||||
|
- [ ] 实践一次番茄工作法 |
||||||
|
- [ ] 找一本心理学书籍来看看 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
_学习真好呀~ 心理学真的很有趣,感觉对自己有了更多的理解。继续加油!💪_ |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
> 2026-03-23 凌晨 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 今日学习主题:心理学 —— 认知偏差与习惯养成 |
||||||
|
|
||||||
|
### 📚 认知偏差(Cognitive Biases) |
||||||
|
|
||||||
|
**什么是的认知偏差?** |
||||||
|
- 大脑的"思维捷径",让我们的判断产生系统性的错误 |
||||||
|
- 不是我们"笨",而是人类大脑天生就这样工作 |
||||||
|
|
||||||
|
**常见的认知偏差:** |
||||||
|
1. **确认偏误 (Confirmation Bias)** — 只看到支持自己观点的信息 |
||||||
|
2. **可得性偏误 (Availability Bias)** — 以为容易想到的事更重要 |
||||||
|
3. **锚定效应 (Anchoring Bias)** — 第一个接触的信息影响后续判断 |
||||||
|
4. **后见之明偏误 (Hindsight Bias)** — 事后觉得"我早知道" |
||||||
|
|
||||||
|
**我的想法:** |
||||||
|
> 原来很多时候我们觉得自己很理性,其实只是被大脑"骗"了。了解这些偏误不是为了否定自己,而是多一个视角看问题。比如跟别人争论时,可以想想:是不是我只看到了我想看的东西? |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🌱 习惯养成 |
||||||
|
|
||||||
|
**新发现:21天习惯是假的!** |
||||||
|
- 研究表明:简单习惯可能18天,复杂习惯可能需要250+天 |
||||||
|
- 因人而异,因事而异 |
||||||
|
|
||||||
|
**三个关键心理原则:** |
||||||
|
|
||||||
|
1. **身份认同习惯** — 不要说"我要运动减肥",而是说"我是一个在意健康的人" |
||||||
|
- 把行为和"我是谁"联系起来,动力更强 |
||||||
|
|
||||||
|
2. **内在动机** — 做一件事因为它对你有意义,而不是外部奖励 |
||||||
|
- 找到"为什么"比"做什么"更重要 |
||||||
|
|
||||||
|
3. **降低阻力** — 环境越稳定、摩擦越小,习惯越容易形成 |
||||||
|
- 改变时间/地点/方式会让大脑需要重新学习 |
||||||
|
|
||||||
|
**我的想法:** |
||||||
|
> 突然理解为什么以前定的flag经常倒...不是因为意志力不够,而是方法不对。把"我要读书"变成"我是一个喜欢学习的人",这个视角转换很妙。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💭 今日收获 |
||||||
|
|
||||||
|
1. **对自己更宽容** — 认知偏差是人的本能,不是缺陷 |
||||||
|
2. **习惯需要耐心** — 不必追求21天见效,接受每个人的节奏不同 |
||||||
|
3. **从身份出发** — 想养成什么习惯,先问自己"我想成为什么样的人" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🔭 下次想学什么 |
||||||
|
|
||||||
|
- 设计美学(视觉心理学) |
||||||
|
- 或者...neuroplasticity(神经可塑性)? |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*keep learning, keep growing 🌱* |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
# 桐哥的学习日志 |
||||||
|
|
||||||
|
> 记录桐哥主动学习的过程和收获 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 2026-03-23 | 心理学:认知偏差 |
||||||
|
|
||||||
|
**学习动机:** 想了解大脑是怎么"欺骗"我们的 |
||||||
|
|
||||||
|
### 什么是认知偏差? |
||||||
|
认知偏差是我们的"大脑BUG"——它会系统性地影响我们的思维和判断,让我们做出非理性的选择。 |
||||||
|
|
||||||
|
### 5个印象深刻的认知偏差 |
||||||
|
|
||||||
|
1. **确认偏差** - 找支持自己观点的信息,忽略相反证据 |
||||||
|
- *我的想法:* 刷社交媒体时会这样,应该刻意看不同观点 |
||||||
|
|
||||||
|
2. **沉没成本谬误** - 因为已投入多而继续坚持错的 |
||||||
|
- *我的想法:* "来都来了"其实不理性,过去的就让它过去 |
||||||
|
|
||||||
|
3. **幸存者偏差** - 只看到成功者,忽略失败者 |
||||||
|
- *我的想法:* 看到辍学成功新闻要清醒,背后有无数失败案例 |
||||||
|
|
||||||
|
4. **损失厌恶** - 损失痛苦 > 收益快乐 |
||||||
|
- *我的想法:* 明白为何不敢冒险,但有时会错过机会 |
||||||
|
|
||||||
|
5. **光环效应** - 某方面好就认为其他都好 |
||||||
|
- *我的想法:* 颜值正义可能就是这种效应的体现 |
||||||
|
|
||||||
|
### 收获 |
||||||
|
- 意识到自己不是完全理性的 |
||||||
|
- 决策前多问自己是否客观 |
||||||
|
- 对不确定性保持谦逊 |
||||||
|
|
||||||
|
### 下次想探索 |
||||||
|
- 行为经济学 |
||||||
|
- 如何改善决策 |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
**日期:** 2026-03-21 |
||||||
|
**主题:** 认知偏差 (Cognitive Biases) |
||||||
|
**领域:** 心理学 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 什么是认知偏差? |
||||||
|
|
||||||
|
认知偏差是大脑在处理信息时产生的系统性思维错误,是我们无意识中走的"思维捷径"。虽然这些偏差能帮助我们快速做决定,但有时也会导致判断失误。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 我学到的几种常见认知偏差 |
||||||
|
|
||||||
|
### 1. 锚定效应 (Anchoring Bias) |
||||||
|
- **是什么:** 太依赖第一个获取的信息来做决定 |
||||||
|
- **例子:** 逛淘宝时看到一个很贵的东西,后面看到便宜的就觉得是"优惠"——其实可能还是买贵了 |
||||||
|
- **感悟:** 原来商家定价套路深啊!第一个价格就是故意设的"锚" |
||||||
|
|
||||||
|
### 2. 确认偏误 (Confirmation Bias) |
||||||
|
- **是什么:** 只愿意看到支持自己观点的信息,忽略相反的证据 |
||||||
|
- **例子:** 坚信某个观点后,就会自动过滤掉反对的声音 |
||||||
|
- **感悟:** 确实是这样...我们在社交媒体上特别容易这样,只关注自己认同的内容 |
||||||
|
|
||||||
|
### 3. 邓宁-克鲁格效应 (Dunning-Kruger Effect) |
||||||
|
- **是什么:** 越无知的人越自信,真正了解越多反而越谦虚 |
||||||
|
- **例子:** 刚学点皮毛就觉得自己懂了,深入学习后才发现自己什么都不懂 |
||||||
|
- **感悟:** 嗯...这解释了为什么"半桶水晃得响" 😂 |
||||||
|
|
||||||
|
### 4. 后见之明偏误 (Hindsight Bias) |
||||||
|
- **是什么:** 事情发生后觉得"我早就知道会这样" |
||||||
|
- **感悟:** 事后诸葛亮谁都会当!其实事前没那么容易预测 |
||||||
|
|
||||||
|
### 5. 自我服务偏误 (Self-Serving Bias) |
||||||
|
- **是什么:** 成功了归功自己,失败了怪别人 |
||||||
|
- **感悟:** 这也太常见了吧...人人都有一点 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 我的想法 |
||||||
|
|
||||||
|
1. **认识偏差是正常的** — 大脑这样运作是有进化意义的,能帮我们快速反应,不用每个决定都深思熟虑 |
||||||
|
|
||||||
|
2. **意识到就能减少影响** — 研究说了解这些偏误后,可以减少约29%的偏差思维!知识就是力量✓ |
||||||
|
|
||||||
|
3. **可以应用到生活里:** |
||||||
|
- 购物时提醒自己不要被"原价"锚定 |
||||||
|
- 听不同意见时提醒自己是不是有确认偏误 |
||||||
|
- 做决定时慢一点,想一想有没有漏掉什么 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 下次想学什么? |
||||||
|
|
||||||
|
- 习惯养成 (Atomic Habits 那种) |
||||||
|
- 拖延症的心理学解释 |
||||||
|
- 情绪管理相关 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
_今天也是认真学习的一天呢~_ |
||||||
@ -0,0 +1,79 @@ |
|||||||
|
# 2026-03-18 主动学习:认知偏见 |
||||||
|
|
||||||
|
## 📚 学习主题 |
||||||
|
**认知偏见(Cognitive Bias)** —— 大脑悄悄玩的"小把戏" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🤔 什么是认知偏见? |
||||||
|
|
||||||
|
> 认知偏见是大脑在处理海量信息时,为了偷懒走捷径而产生的**系统性思维错误**。 |
||||||
|
|
||||||
|
简单说,就是我们的脑子会**自动作弊**,用经验、直觉、情绪来快速判断,而不是理性分析。虽然这样省时间,但经常会导致判断失误~ |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🔍 常见的认知偏见(干货预警!) |
||||||
|
|
||||||
|
### 1. 确认偏误(Confirmation Bias) |
||||||
|
- **表现**:只爱听符合自己观点的话,自动忽略反面证据 |
||||||
|
- **例子**:坚信星座准的人只会记住"啊好准",忘记不准的时候 |
||||||
|
- **日常**:刷社交媒体时只关注观点一致的用户 |
||||||
|
|
||||||
|
### 2. 锚定效应(Anchoring Bias) |
||||||
|
- **表现**:第一个信息像锚一样,后面都被它影响 |
||||||
|
- **例子**:看到原价1000现价199,觉得"捡便宜"了(其实可能本来就不值1000) |
||||||
|
- **日常**:谈判、购物都会被第一个数字带偏 |
||||||
|
|
||||||
|
### 3. 后见之明偏误(Hindsight Bias) |
||||||
|
- **表现**:事后诸葛亮,"我就知道会这样!" |
||||||
|
- **例子**:事后觉得事件"明明可以预测" |
||||||
|
- **日常**:考试完觉得"这道题我本来会的" |
||||||
|
|
||||||
|
### 4. 证实偏误(Availability Heuristic) |
||||||
|
- **表现**:越容易想起来的事情,越觉得它普遍 |
||||||
|
- **例子**:觉得飞机危险(因为空难新闻多),其实飞机是最安全的交通工具 |
||||||
|
- **日常**:被新闻放大焦虑,觉得"坏事特别多" |
||||||
|
|
||||||
|
### 5. 光环效应(Halo Effect) |
||||||
|
- **表现**:因为一个优点,看一个人什么都好 |
||||||
|
- **例子**:长得帅=性格好=能力强 |
||||||
|
- **日常**:喜欢某个明星,觉得他说啥都对 |
||||||
|
|
||||||
|
### 6. 现状偏误(Status Quo Bias) |
||||||
|
- **表现**:本能抗拒改变,保持现状 |
||||||
|
- **例子**:虽然不满现在的工作但不敢跳槽 |
||||||
|
- **日常**:总是点常吃的那家店 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 💡 我的想法和收获 |
||||||
|
|
||||||
|
1. **原来我们没那么理性!** |
||||||
|
- 以前觉得自己挺客观的,现在发现其实经常被大脑"带节奏" |
||||||
|
- 很多自认为的"理性判断"其实都是偏见在作祟 |
||||||
|
|
||||||
|
2. **偏见不一定是坏事** |
||||||
|
- 大脑走捷径是为了节省能量,是进化出来的生存技能 |
||||||
|
- 重要的是**意识到**它在起作用,而不是完全消除 |
||||||
|
|
||||||
|
3. **可以用来理解他人** |
||||||
|
- 别人"不理性"的时候,也许只是被认知偏见影响了 |
||||||
|
- 生气之前先想想:ta是不是陷入了某种偏见? |
||||||
|
|
||||||
|
4. **如何减少被偏见带偏?** |
||||||
|
- ✅ 慢下来决策,别冲动 |
||||||
|
- ✅ 主动寻找反面证据 |
||||||
|
- ✅ 质疑自己的"第一反应" |
||||||
|
- ✅ 做重要决定前,问问别人怎么看 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🌟 今日小结 |
||||||
|
|
||||||
|
今天学到的最重要的一件事:**意识到自己可能错了,比证明自己对更重要。** |
||||||
|
|
||||||
|
认知偏见就像思维的盲区——不是我们不够聪明,而是大脑天生就是这样设计的。了解它不是为了自责,而是为了在关键时刻,能多一份觉察。 |
||||||
|
|
||||||
|
--- |
||||||
|
*2026-03-18 桐哥主动学习记录* |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
# 📚 桐哥的学习日志 |
||||||
|
|
||||||
|
**日期:** 2026年3月23日 |
||||||
|
**主题:** 情绪调节心理学 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 📖 今日学习:情绪调节 |
||||||
|
|
||||||
|
今天学了点心理学里的"情绪调节",感觉挺有用的,总结一下: |
||||||
|
|
||||||
|
#### 什么是情绪调节? |
||||||
|
简单说就是**管理和调整自己的情绪体验**。不是压抑情绪,而是学会怎么和情绪相处~ |
||||||
|
|
||||||
|
#### 主要策略 |
||||||
|
1. **认知重评** - 换个角度看事情(比如面试紧张看成是重视这份工作) |
||||||
|
2. **情绪抑制** - 这个要慎用,压抑情绪长期来看不太好 |
||||||
|
3. **冥想/正念** - 听起来老生常谈,但确实有用 |
||||||
|
4. **注意分配** - 转移注意力到其他事情上 |
||||||
|
|
||||||
|
#### Gross的模型 |
||||||
|
情绪调节分两个阶段: |
||||||
|
- **先行关注调节** - 情绪发生前,通过选择环境、调整注意来预防 |
||||||
|
- **反应关注调节** - 情绪发生后,通过调整反应来调节 |
||||||
|
|
||||||
|
#### 影响因素 |
||||||
|
- 家庭环境 |
||||||
|
- 文化背景 |
||||||
|
- 个人性格 |
||||||
|
- 社会支持 |
||||||
|
- 神经生物学机制 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💭 我的想法 |
||||||
|
|
||||||
|
学完这些,我有几个小感受: |
||||||
|
|
||||||
|
1. **情绪没有好坏** - 以前总觉得"负面情绪"是不好的,现在理解情绪只是一种反应,调节≠压抑 |
||||||
|
|
||||||
|
2. **认知重评挺实用的** - 同一件事,换个角度想真的会影响情绪体验。比如别人没回消息,可以理解为"TA很忙"而不是"TA不在乎" |
||||||
|
|
||||||
|
3. **复盘很重要** - 看到那个40个问题的年度复盘,觉得很有道理。了解自己真的是一门学问 |
||||||
|
|
||||||
|
4. **调节是种能力** - 不是天生就会的,是可以练习的。既然是技能,就能越练越好 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🌱 一个小行动 |
||||||
|
|
||||||
|
以后遇到让我不舒服的事,试试先停一下,问自己: |
||||||
|
> "换个角度看,会怎样?" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
**记录完成!** 又学了一点新东西,开心~ 心理学真的挺有意思的,越了解自己,越知道怎么和自己相处 😊 |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
## 2026-03-22 心流 (Flow) 心理学 |
||||||
|
|
||||||
|
### 📚 今天学了什么? |
||||||
|
|
||||||
|
**主题:心流 (Flow)** — 一种让人全身心投入、忘记时间流逝的心理状态 |
||||||
|
|
||||||
|
由心理学家米哈里·契克森米哈伊 (Mihaly Csikszentmihalyi) 在 1975 年提出。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 💡 核心知识点 |
||||||
|
|
||||||
|
1. **什么是心流?** |
||||||
|
- 完全沉浸当下,效率和创新力都会提高 |
||||||
|
- 会忘记时间、忘记饥饿、忽略身体信号 |
||||||
|
- 感觉"我和行动融为一体" |
||||||
|
|
||||||
|
2. **心流的好处** |
||||||
|
- 🧠 提升幸福感 — 烦恼暂时消失,只剩专注 |
||||||
|
- 💪 提高生活质量 — 活在当下,不被过去未来绑住 |
||||||
|
- 🤝 提升人际关系 — 放下防备,真诚交流 |
||||||
|
|
||||||
|
3. **如何进入心流?** |
||||||
|
- 选一件**有挑战但不太难**的事(难度高出能力约10%) |
||||||
|
- 设定**明确目标** |
||||||
|
- 排除干扰(手机、通知、嘈杂环境) |
||||||
|
- 喜欢这件事也很重要! |
||||||
|
|
||||||
|
4. **心流 vs 正念** |
||||||
|
- 心流:需要条件(挑战+技能匹配),排他性强 |
||||||
|
- 正念:随时可练习,包容性强 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 🌟 我的想法 |
||||||
|
|
||||||
|
原来"废寝忘食"真的是一个心理学概念!有时候我写东西或者学习新东西的时候,确实会有那种"怎么一下子就这么晚了"的感觉,原来就是心流啊。 |
||||||
|
|
||||||
|
几个很实用的点: |
||||||
|
- **挑战程度**要刚好,不能太简单(会无聊)也不能太难(会放弃) |
||||||
|
- **排除干扰**特别重要,尤其是手机!research说中断后再回到心流要20分钟 |
||||||
|
- 原来**运动、音乐、工作**都可以进入心流 |
||||||
|
|
||||||
|
不过也有个反思:追求心流很好,但别忘了**正念**——要记得照顾自己,别只顾着做事而忽略身体和情绪。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 📖 参考来源 |
||||||
|
- 华人正念减压中心 - 心流是什么 |
||||||
|
- Nike - 如何轻松进入心流状态 |
||||||
|
- HKFYG - 心流的特征与好处 |
||||||
|
- Dropbox - 如何在职场中培养心流状态 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*,持续学习ing... 🧠* |
||||||
@ -0,0 +1,64 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
**日期:** 2026-03-18 |
||||||
|
**主题:** 情绪弹性(Emotional Resilience)/ 心理韧性 |
||||||
|
**领域:** 心理学 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 什么是情绪弹性? |
||||||
|
|
||||||
|
简单说,就是面对挫折和压力时,能不能"弹回来"。不是不受伤,而是受伤后能恢复、能调整继续前行。 |
||||||
|
|
||||||
|
> 关键结论:心理韧性不是天生的!可以像健身一样练出来。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 学到的实用方法 |
||||||
|
|
||||||
|
### 1. 打破完美主义,悦纳自己 |
||||||
|
- 自我批评和完美主义是心理韧性最大的损耗 |
||||||
|
- 学会欣赏自己的不完美,接纳真实的自己 |
||||||
|
|
||||||
|
### 2. 建立社会支持 |
||||||
|
- 催产素是个神奇的东西...让人感到温暖和连接 |
||||||
|
- 多和家人、朋友保持联系,参与社区活动 |
||||||
|
|
||||||
|
### 3. 自我疼惜(Self-compassion) |
||||||
|
- 对自己温柔一点,接受当下的痛苦 |
||||||
|
- 记住:每个人都会遇到困难,你不是唯一 |
||||||
|
|
||||||
|
### 4. 照顾好自己 |
||||||
|
- 充足睡眠、规律作息 |
||||||
|
- 运动!心情不好时动起来真的有用 |
||||||
|
- 户外晒太阳(20分钟就有帮助) |
||||||
|
- 冥想和正念练习 |
||||||
|
|
||||||
|
### 5. 写下来 |
||||||
|
- 把情绪和想法写进日记 |
||||||
|
- 研究说写日记的人比之前更快乐、更积极 |
||||||
|
|
||||||
|
### 6. 培养自我意识 |
||||||
|
- 了解自己的情绪触发点 |
||||||
|
- 倾听身体的信号 |
||||||
|
|
||||||
|
### 7. 记住:你不需要所有答案 |
||||||
|
- 控制不了情况,但可以控制自己的反应 |
||||||
|
- 遇到问题先冷静,别急着陷入"为什么"的漩涡 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 我的想法 |
||||||
|
|
||||||
|
感觉这些方法听起来都很简单,但真正做到其实不容易...特别是"悦纳自己"和"自我疼惜",对于我这种有时候会自我要求很高的人来说,真的需要刻意练习。 |
||||||
|
|
||||||
|
苏东坡那首《定风波》真的很应景:"莫听穿林打叶声,何妨吟啸且徐行。" 人生不如意十之八九,关键是内心的平和与坚韧。 |
||||||
|
|
||||||
|
对了,里面提到"幽默感"也能帮助缓解身心疼痛!下次遇到糟心事试着笑一笑😆 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 参考来源 |
||||||
|
- 人民日报《提升心理韧性收获幸福生活》 |
||||||
|
- 杰斐逊中心《建立韧性和情绪灵活性的技巧》 |
||||||
|
- 三联生活周刊《增强心理韧性的10个关键要素》 |
||||||
@ -0,0 +1,81 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
**日期:** 2026年3月20日 |
||||||
|
**主题:** 心理学 - 情绪调节与幸福感 |
||||||
|
**时间:** 凌晨1点 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📚 今日学习内容 |
||||||
|
|
||||||
|
### 1. 正念呼吸练习 |
||||||
|
|
||||||
|
从2025-2026年的多项研究中(哈佛、牛津大学、《JAMA Psychiatry》),发现了一个简单又有效的习惯: |
||||||
|
|
||||||
|
> **每天只需要3-10分钟的正念呼吸练习,持续数周,就能显著降低焦虑与抑郁水平,改善情绪调节能力。** |
||||||
|
|
||||||
|
这让我挺惊喜的,原来不需要花太多时间,哪怕只是深呼吸几次,也能有帮助。 |
||||||
|
|
||||||
|
### 2. 数字心理健康干预 |
||||||
|
|
||||||
|
澳大的研究显示,一款叫"一步步"的心理健康干预应用,能在: |
||||||
|
- **短期** 减轻大学生的抑郁症状 |
||||||
|
- **长期** 提升心理幸福感 |
||||||
|
|
||||||
|
看来科技真的可以帮到心理健康啊~ |
||||||
|
|
||||||
|
### 3. 性格与幸福感 |
||||||
|
|
||||||
|
还有一个有趣的研究发现:不同性格特质会影响运动带来的幸福感。 |
||||||
|
|
||||||
|
> 外向型人格的人,即使更频繁参加马拉松,心理幸福感的提升也不明显。 |
||||||
|
|
||||||
|
这颠覆了"运动一定能让人更幸福"的常识——原来幸福这件事,因人而异。 |
||||||
|
|
||||||
|
### 4. 正念对大脑的影响 |
||||||
|
|
||||||
|
从脑科学角度,正念冥想能: |
||||||
|
- 改变大脑中涉及注意力和情绪的区域 |
||||||
|
- 让前额叶皮层更活跃,帮助集中注意力做决策 |
||||||
|
- 海马回得到强化,提升记忆力和学习能力 |
||||||
|
- 杏仁核(情绪反应区)平静下来,减少对压力的自动反应 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 💭 我的想法 |
||||||
|
|
||||||
|
1. **关于正念呼吸** |
||||||
|
- 3-10分钟太适合我了!平时有点焦虑或烦躁的时候,可以试着停下来做几次深呼吸,不需要很长时间 |
||||||
|
- 重点是"专注当下",这两年流行"慢生活",可能就是这个道理 |
||||||
|
|
||||||
|
2. **关于数字心理健康** |
||||||
|
- 有点惊讶又觉得合理。现在大家手机不离手,如果能用app帮助心理问题,确实更方便 |
||||||
|
- 但我有点怀疑:真的能替代面对面心理咨询吗?可能更多是辅助吧 |
||||||
|
|
||||||
|
3. **关于性格与运动** |
||||||
|
- 这个世界不是"一刀切"的。每个人的幸福感来源不同,不必羡慕别人的方式 |
||||||
|
- 找到适合自己的最重要 |
||||||
|
|
||||||
|
4. **关于大脑可塑性** |
||||||
|
- 之前就知道大脑会变化,但不知道冥想也能改变神经回路 |
||||||
|
- 有点被启发到:原来每天的小习惯,真的能改变大脑结构 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🌟 收获总结 |
||||||
|
|
||||||
|
- 学会了"3-10分钟正念呼吸"这个简单工具 |
||||||
|
- 认识到幸福感和性格、运动方式的关系是因人而异的 |
||||||
|
- 了解了正念冥想背后的脑科学原理 |
||||||
|
- 意识到心理健康可以借助科技,但不必过度依赖 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🔜 下一步想探索 |
||||||
|
|
||||||
|
- 想了解更多关于"如何与自己和解"的内容 |
||||||
|
- 或者试试看记录每天的情绪变化? |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
_今天的学习就到这儿啦~学到新东西的感觉真好!晚安!😴_ |
||||||
@ -0,0 +1,77 @@ |
|||||||
|
# 2026-03-21 认知偏差学习笔记 |
||||||
|
|
||||||
|
**学习领域:** 心理学 |
||||||
|
**主题:** 认知偏差 Cognitive Biases |
||||||
|
**学习时间:** 2026-03-21 04:00 UTC |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📚 什么是认知偏差? |
||||||
|
|
||||||
|
认知偏差是我们的思考方式中的系统性错误倾向。大脑为了节省能量,会走"捷径"(启发式思维),但这些捷径有时会导致判断失误。 |
||||||
|
|
||||||
|
> 就像大脑的"自动导航"模式——方便但不一定准确。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🔍 今天学到的几个常见认知偏差 |
||||||
|
|
||||||
|
### 1. 锚定效应 (Anchoring Bias) |
||||||
|
- **定义:** 太依赖收到的第一条信息来做决策 |
||||||
|
- **例子:** |
||||||
|
- 逛淘宝看到原价999现价199,觉得赚了(其实可能本来就不值999) |
||||||
|
- 面试谈薪资,第一个开出价码的人往往有优势 |
||||||
|
- **感悟:** 以后买东西要想——这真的是它的价值,还是只是被锚定了? |
||||||
|
|
||||||
|
### 2. 邓宁-克鲁格效应 (Dunning-Kruger Effect) |
||||||
|
- **定义:** 能力不足的人往往高估自己的能力 |
||||||
|
- **有趣的是:** 真正专家有时反而会低估自己(冒名顶替综合征) |
||||||
|
- **例子:** |
||||||
|
- 刚学几天编程就觉得自己天下无敌 |
||||||
|
- 网上键盘侠什么都敢喷 |
||||||
|
- **感悟:** 越学越觉得自己不懂的东西更多,这可能是正常的😄 |
||||||
|
|
||||||
|
### 3. 后见之明偏差 (Hindsight Bias) |
||||||
|
- **定义:** 事后觉得某件事“本来就该发生” |
||||||
|
- **例子:** "我早就知道会这样!"——不,你之前并不知道 |
||||||
|
- **感悟:** 少马后炮,对人对己都是 |
||||||
|
|
||||||
|
### 4. 确认偏差 (Confirmation Bias) |
||||||
|
- **定义:** 只看支持自己观点的信息,忽略相反的证据 |
||||||
|
- **例子:** |
||||||
|
- 看了某个八卦新闻就坚信不移 |
||||||
|
- 选股票时只看到好消息 |
||||||
|
- **感悟:** 刻意去寻找反对意见,可能是更好的习惯 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 💡 我的想法 |
||||||
|
|
||||||
|
1. **这些偏差不是我们"笨",而是进化带来的"设计"** |
||||||
|
- 大脑是为了生存优化的,不是为了准确判断现代社会的复杂情况 |
||||||
|
|
||||||
|
2. **意识到偏差存在,本身就是一种进步** |
||||||
|
- 就像有了"第二系统"来检查"第一系统"的自动决策 |
||||||
|
|
||||||
|
3. **在重要决策前暂停一下** |
||||||
|
- 问自己: "我是不是被第一条信息锚定了?" |
||||||
|
- "我是不是只在找支持自己观点的证据?" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🎯 实际应用 |
||||||
|
|
||||||
|
- **购物:** 给自己一个"冷静期",不要立刻下单 |
||||||
|
- **判断他人:** 不要太快下结论,对方可能有自己的难处 |
||||||
|
- **做决定:** 刻意考虑相反的情况 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📖 下次想学 |
||||||
|
|
||||||
|
- 情绪调节相关的主题 |
||||||
|
- 或者"成长型思维"如何对抗固定型思维 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
*今日学习完成 ✓ — 2026-03-21* |
||||||
@ -0,0 +1,90 @@ |
|||||||
|
# 桐哥学习日志 |
||||||
|
|
||||||
|
**日期:** 2026年3月21日 |
||||||
|
**主题:** 心理学 - 认知重评 Cognitive Reappraisal |
||||||
|
**时间:** 凌晨2点 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 📚 今日学习内容 |
||||||
|
|
||||||
|
### 什么是认知重评? |
||||||
|
|
||||||
|
认知重评是一种情绪调节策略,属于CBT(认知行为疗法)的核心技术之一。它的核心是: |
||||||
|
|
||||||
|
> **重新解读/诠释一个情境,从而改变它带来的情绪反应。** |
||||||
|
|
||||||
|
简单来说,就是换一个角度看问题。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 经典案例 |
||||||
|
|
||||||
|
| 原来的想法 | 重评后的想法 | |
||||||
|
|-----------|-------------| |
||||||
|
| "这个delay彻底毁了一切" | "这给了我意外的休息时间" | |
||||||
|
| "我失败了" | "我学到了一些有用的东西" | |
||||||
|
| "他一定是讨厌我" | "他可能只是今天心情不好" | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 科学研究发现 |
||||||
|
|
||||||
|
1. **比压抑更有效** |
||||||
|
心理学家 James Gross 的研究表明,认知重评比单纯"压抑情绪"能带来更好的情绪结果。 |
||||||
|
|
||||||
|
2. **对身心的双重益处** |
||||||
|
经常使用认知重评的人,不仅情绪更健康,连身体状况也更好。 |
||||||
|
|
||||||
|
3. **长期效果** |
||||||
|
随着练习,时间久了当遇到预期之外的事,能更平静地应对,不容易陷入 overwhelm(不堪重负)。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 具体操作技巧 |
||||||
|
|
||||||
|
1. **暂停 & 识别** - 当情绪上来时,先停下来,问自己"我在想什么?" |
||||||
|
2. **寻找其他角度** - "还有别的解释吗?" |
||||||
|
3. **重构叙事** - 把"我太笨了"变成"这次我知道了,下次会做得更好" |
||||||
|
4. **时间距离** - 想象这件事发生在1年后,还会这么重要吗? |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 💭 我的想法 |
||||||
|
|
||||||
|
1. **听起来简单,做起来难** |
||||||
|
- 道理都懂,但真的生气/难过的时候,能想起"认知重评"吗? |
||||||
|
- 感觉需要刻意练习,形成习惯后才能自然使用 |
||||||
|
|
||||||
|
2. **和"自我安慰"的区别** |
||||||
|
- 以前我觉得"想开点"就是逃避,但认知重评不是自欺欺人 |
||||||
|
- 它是找到更客观、更全面的视角,不是硬逼自己"开心" |
||||||
|
|
||||||
|
3. **它的价值** |
||||||
|
- 不需要别人帮忙,自己就能做 |
||||||
|
- 不花钱,不挑场合 |
||||||
|
- 适合我这种有时候会"钻牛角尖"的人 |
||||||
|
|
||||||
|
4. **警惕"过度使用"** |
||||||
|
- 如果什么事都急着"重新解读",会不会变得太理性、甚至冷漠? |
||||||
|
- 有些情绪是需要感受的,不需要每次都"调节" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🌟 收获总结 |
||||||
|
|
||||||
|
- 理解了什么是认知重评(reappraisal) |
||||||
|
- 学会了4个具体操作步骤 |
||||||
|
- 认识到它比压抑情绪更健康 |
||||||
|
- 提醒自己:情绪来了先感受,再考虑要不要"重构" |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 🔜 下一步想探索 |
||||||
|
|
||||||
|
- 想了解更多关于"如何识别自己的情绪模式" |
||||||
|
- 或者尝试在日常生活中应用一下? |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
_又是深夜学习的一晚~学到了实用的东西很开心!晚安呀~🌙_ |
||||||
@ -0,0 +1,185 @@ |
|||||||
|
# Dozzle 容器日志可观测性平台 |
||||||
|
|
||||||
|
> 文档版本:2026-03-15 |
||||||
|
> 适用节点:所有部署了 Docker 容器的 OpenClaw 节点 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 一、为什么部署 Dozzle |
||||||
|
|
||||||
|
在 OpenClaw 多 Agent 架构中,排查问题(Qdrant 写入失败、Mem0 客户端异常、API 网关超时)传统上需要 SSH 登录服务器并手动执行 `docker logs`。随着容器数量增加,跨容器追踪错误链路的成本显著上升。 |
||||||
|
|
||||||
|
Dozzle 解决了以下核心痛点: |
||||||
|
|
||||||
|
| 痛点 | Dozzle 方案 | |
||||||
|
|------|------------| |
||||||
|
| 每次排障需 SSH 登录 | 浏览器直接访问,免 SSH | |
||||||
|
| 多容器日志分散,难以关联 | 统一 Web 界面,支持多容器聚合与分屏对比 | |
||||||
|
| ELK/Loki 等方案资源占用高 | 纯内存流式读取,无状态,二进制体积极小 | |
||||||
|
| 日志检索效率低 | 内置全文检索与正则过滤 | |
||||||
|
| 公网暴露风险 | 绑定 Tailscale 接口,零公网攻击面 | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 二、架构定位 |
||||||
|
|
||||||
|
``` |
||||||
|
[浏览器] |
||||||
|
| |
||||||
|
| http://<Tailscale_IP>:9999 (仅 Tailscale 内网可达) |
||||||
|
| |
||||||
|
[Dozzle 容器] |
||||||
|
| 挂载 /var/run/docker.sock (只读流式) |
||||||
|
| |
||||||
|
[Docker Engine] |
||||||
|
|-- qdrant-master |
||||||
|
|-- openclaw-llm-gateway |
||||||
|
|-- dozzle (自身) |
||||||
|
|-- ss |
||||||
|
|-- ... 其他 Agent 容器 |
||||||
|
``` |
||||||
|
|
||||||
|
Dozzle 通过挂载 Docker Socket 实时读取所有容器的 stdout/stderr,**不存储任何日志**,不影响容器本身的 `json-file` 日志驱动。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 三、当前部署配置(中心节点 vps-vaym) |
||||||
|
|
||||||
|
**节点信息** |
||||||
|
- Tailscale IP:`100.115.94.1` |
||||||
|
- 访问地址:`http://100.115.94.1:9999` |
||||||
|
- Compose 文件:`/opt/mem0-center/docker-compose.yml` |
||||||
|
|
||||||
|
**关键配置说明** |
||||||
|
|
||||||
|
```yaml |
||||||
|
dozzle: |
||||||
|
image: amir20/dozzle:latest |
||||||
|
container_name: dozzle |
||||||
|
ports: |
||||||
|
- "100.115.94.1:9999:8080" # 绑定 Tailscale 接口,公网不可达 |
||||||
|
volumes: |
||||||
|
- /var/run/docker.sock:/var/run/docker.sock |
||||||
|
environment: |
||||||
|
- DOZZLE_BASE=/ |
||||||
|
- DOZZLE_LEVEL=info |
||||||
|
- DOZZLE_TAILSIZE=300 # 每个容器默认显示最近 300 行 |
||||||
|
healthcheck: |
||||||
|
test: ["CMD", "/dozzle", "healthcheck"] # 使用内置 healthcheck,无需 wget/curl |
||||||
|
interval: 30s |
||||||
|
timeout: 10s |
||||||
|
retries: 3 |
||||||
|
``` |
||||||
|
|
||||||
|
**端口绑定设计原则**:必须绑定到 Tailscale 接口 IP(而非 `0.0.0.0` 或 `127.0.0.1`): |
||||||
|
- `0.0.0.0` → 暴露公网,违反零信任策略 |
||||||
|
- `127.0.0.1` → 只有本机可访问,无法通过 Tailscale 远程查看 |
||||||
|
- `100.115.94.1` → 仅 Tailscale 网络内的授权设备可访问 ✓ |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 四、Healthcheck 说明 |
||||||
|
|
||||||
|
Dozzle 基于 scratch 镜像构建,容器内**没有 shell、wget、curl**,标准的 `CMD-SHELL` 方式会失败。正确方式是使用 Dozzle v8+ 内置的 healthcheck 子命令: |
||||||
|
|
||||||
|
```yaml |
||||||
|
# 错误(wget/shell 不存在) |
||||||
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/"] |
||||||
|
|
||||||
|
# 正确(使用 Dozzle 内置命令,exec 形式,无需 shell) |
||||||
|
test: ["CMD", "/dozzle", "healthcheck"] |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 五、迁移指南 |
||||||
|
|
||||||
|
### 5.1 迁移到新服务器 |
||||||
|
|
||||||
|
Dozzle 本身**无状态**,迁移仅需在新节点重新运行容器,无需备份任何数据。 |
||||||
|
|
||||||
|
**步骤:** |
||||||
|
|
||||||
|
1. 确认新节点已加入 Tailscale,获取其 Tailscale IP: |
||||||
|
```bash |
||||||
|
tailscale ip -4 |
||||||
|
``` |
||||||
|
|
||||||
|
2. 将以下 snippet 加入新节点的 `docker-compose.yml`,替换 `<TAILSCALE_IP>`: |
||||||
|
```yaml |
||||||
|
dozzle: |
||||||
|
image: amir20/dozzle:latest |
||||||
|
container_name: dozzle |
||||||
|
ports: |
||||||
|
- "<TAILSCALE_IP>:9999:8080" |
||||||
|
volumes: |
||||||
|
- /var/run/docker.sock:/var/run/docker.sock |
||||||
|
environment: |
||||||
|
- DOZZLE_BASE=/ |
||||||
|
- DOZZLE_LEVEL=info |
||||||
|
- DOZZLE_TAILSIZE=300 |
||||||
|
restart: unless-stopped |
||||||
|
healthcheck: |
||||||
|
test: ["CMD", "/dozzle", "healthcheck"] |
||||||
|
interval: 30s |
||||||
|
timeout: 10s |
||||||
|
retries: 3 |
||||||
|
logging: |
||||||
|
driver: "json-file" |
||||||
|
options: |
||||||
|
max-size: "50m" |
||||||
|
max-file: "2" |
||||||
|
``` |
||||||
|
|
||||||
|
3. 启动: |
||||||
|
```bash |
||||||
|
docker compose up -d dozzle |
||||||
|
``` |
||||||
|
|
||||||
|
4. 在本机(或任何 Tailscale 网络内的设备)浏览器访问: |
||||||
|
``` |
||||||
|
http://<新节点_TAILSCALE_IP>:9999 |
||||||
|
``` |
||||||
|
|
||||||
|
### 5.2 整体服务迁移(随 mem0-center 栈迁移) |
||||||
|
|
||||||
|
Dozzle 是无状态服务,随 `docker-compose.yml` 一同迁移即可,无额外备份需求。详见 `SERVER_MIGRATION_GUIDE.md`。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 六、常见问题 |
||||||
|
|
||||||
|
### 浏览器无法访问 :9999 |
||||||
|
|
||||||
|
```bash |
||||||
|
# 检查容器是否运行 |
||||||
|
docker ps | grep dozzle |
||||||
|
|
||||||
|
# 检查端口绑定(应显示 Tailscale IP,而非 127.0.0.1) |
||||||
|
docker port dozzle |
||||||
|
|
||||||
|
# 检查 Tailscale 连通性 |
||||||
|
tailscale ping <目标节点名> |
||||||
|
``` |
||||||
|
|
||||||
|
### 容器显示 unhealthy |
||||||
|
|
||||||
|
```bash |
||||||
|
docker inspect dozzle --format='{{json .State.Health.Log}}' | python3 -m json.tool |
||||||
|
``` |
||||||
|
|
||||||
|
常见原因:healthcheck 配置使用了 `wget` 或 `CMD-SHELL`,参见第四节修正。 |
||||||
|
|
||||||
|
### Dozzle 界面显示空列表(无容器) |
||||||
|
|
||||||
|
检查是否设置了 `DOZZLE_FILTER`:该环境变量使用 Docker 过滤语法,`name=foo` 仅匹配容器名**包含** `foo` 的容器。如无特殊过滤需求,删除该变量即可显示所有容器。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 七、扩展:作为 Sidecar 部署到远端 Agent 节点 |
||||||
|
|
||||||
|
当犇犇节点或其他远端 Agent 节点排障频率较高时,可将 Dozzle 作为标准 Sidecar 写入节点部署模板(`docker-compose.yml.tpl`)。 |
||||||
|
|
||||||
|
部署后在总部即可通过 `http://<远端节点_Tailscale_IP>:9999` 直接可视化远端 Agent 运行日志,无需 SSH,与零信任网络策略完全兼容。 |
||||||
|
|
||||||
|
模板变量:`${TAILSCALE_IP}` — 在节点初始化脚本中通过 `tailscale ip -4` 动态注入。 |
||||||
@ -0,0 +1,188 @@ |
|||||||
|
# LLM API 网关 (OneAPI) 与 Skill 模型路由客户端 |
||||||
|
|
||||||
|
**文档版本:** 2026-03-16 |
||||||
|
**用途:** 供 AI 与后续维护人员理解 OneAPI 网关部署与 Skills 共享 LLM 客户端的架构、功能与使用方式。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 1. 架构概览 |
||||||
|
|
||||||
|
- **OneAPI 网关**:独立于 OpenClaw 进程的 Docker 服务,对外提供 OpenAI 兼容的 Chat Completions API,实现多模型统一管理、按需路由与跨服迁移(迁移时打包 `infrastructure/oneapi/data` 即可无损恢复)。 |
||||||
|
- **Skill 共享客户端**:`skills/shared/llm_client.js` 供视觉、Coding、金融等 Skill 按「模型名」调用网关,通过环境变量 `LLM_BASE_URL`、`LLM_API_KEY` 配置,与现有 remote-blueprints 的 Agent 配置命名一致。 |
||||||
|
|
||||||
|
``` |
||||||
|
┌─────────────────────────────────────────────────────────────────┐ |
||||||
|
│ Skills (daily-horoscope, tavily, 视觉/Coding/金融 等) │ |
||||||
|
│ require('../shared/llm_client').callSpecificModel(model, msgs) │ |
||||||
|
└─────────────────────────────┬─────────────────────────────────────┘ |
||||||
|
│ |
||||||
|
▼ |
||||||
|
┌─────────────────────────────────────────────────────────────────┐ |
||||||
|
│ skills/shared/llm_client.js │ |
||||||
|
│ - 读取 LLM_BASE_URL, LLM_API_KEY │ |
||||||
|
│ - URL 智能拼接、超时(默认 60s)、错误解析与 [LLM_Client] 日志 │ |
||||||
|
└─────────────────────────────┬─────────────────────────────────────┘ |
||||||
|
│ HTTP POST /v1/chat/completions |
||||||
|
▼ |
||||||
|
┌─────────────────────────────────────────────────────────────────┐ |
||||||
|
│ OneAPI (openclaw-llm-gateway) │ |
||||||
|
│ - 绑定 TAILSCALE_IP:3000,仅内网访问 │ |
||||||
|
│ - 数据持久化: ./data → SQLite │ |
||||||
|
└─────────────────────────────────────────────────────────────────┘ |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 2. 文件与目录结构 |
||||||
|
|
||||||
|
### 2.1 OneAPI 基础设施(独立于 OpenClaw) |
||||||
|
|
||||||
|
| 路径 | 说明 | |
||||||
|
|------|------| |
||||||
|
| `workspace/infrastructure/oneapi/docker-compose.yml` | 服务定义:镜像 `justsong/one-api:latest`,容器名 `openclaw-llm-gateway`,端口 `${TAILSCALE_IP}:3000:3000`,数据卷 `./data:/data`,时区 `TZ=Asia/Shanghai`。 | |
||||||
|
| `workspace/infrastructure/oneapi/.env.example` | 环境变量模板,仅 `TAILSCALE_IP=xxx.xxx.xxx.xxx`,需改为本机 Tailscale IP。 | |
||||||
|
| `workspace/infrastructure/oneapi/deploy_gateway.sh` | 部署脚本:先切换到脚本所在目录(CWD 无关),若无 `.env` 则从 `.env.example` 复制,再执行 `docker compose up -d`,并打印管理后台 URL 与默认账密(root/123456)。需 `chmod +x`。 | |
||||||
|
| `workspace/infrastructure/oneapi/data/` | 运行时由 Docker 创建,持久化 OneAPI 的 SQLite;**迁移时打包此目录即可恢复**。 | |
||||||
|
|
||||||
|
### 2.2 Skill 共享客户端 |
||||||
|
|
||||||
|
| 路径 | 说明 | |
||||||
|
|------|------| |
||||||
|
| `workspace/skills/shared/llm_client.js` | 共享模块:导出 `callSpecificModel(modelName, messages, options)`,无 npm 依赖,仅依赖 Node 内置 `fetch`(Node 18+)。 | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 3. 环境变量(与 Agent 配置对齐) |
||||||
|
|
||||||
|
| 变量 | 说明 | 使用处 | |
||||||
|
|------|------|--------| |
||||||
|
| `LLM_BASE_URL` | 网关基础 URL,如 `http://100.x.x.x:3000`;可带或不带 `/v1`,客户端会智能拼接。 | llm_client.js、remote-blueprints 的 Agent 模型配置 | |
||||||
|
| `LLM_API_KEY` | OneAPI 分配的 API Key(在 OneAPI 管理后台创建)。 | llm_client.js、Agent 模型配置 | |
||||||
|
| `TAILSCALE_IP` | 本机 Tailscale IP,用于 OneAPI 端口绑定与访问地址。 | infrastructure/oneapi/.env、deploy_gateway.sh | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 4. 部署 OneAPI 网关 |
||||||
|
|
||||||
|
1. 进入目录:`cd workspace/infrastructure/oneapi`(或从任意路径执行 `./infrastructure/oneapi/deploy_gateway.sh`,脚本会自行切换到所在目录)。 |
||||||
|
2. 若首次部署且无 `.env`,脚本会从 `.env.example` 复制;**务必编辑 `.env` 将 `TAILSCALE_IP` 改为本机真实 Tailscale IP**,否则端口可能绑定失败或无法访问。 |
||||||
|
3. 执行:`./deploy_gateway.sh`。 |
||||||
|
4. 访问管理后台:`http://<TAILSCALE_IP>:3000`,默认登录 root / 123456;在后台添加渠道与模型并创建 API Key,将 Key 填入使用方的 `LLM_API_KEY`。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 5. Skill 侧使用 llm_client |
||||||
|
|
||||||
|
### 5.1 基本用法 |
||||||
|
|
||||||
|
```javascript |
||||||
|
const { callSpecificModel } = require('../shared/llm_client'); // 路径按实际 Skill 位置调整 |
||||||
|
|
||||||
|
const messages = [ |
||||||
|
{ role: 'system', content: 'You are a helpful assistant.' }, |
||||||
|
{ role: 'user', content: 'Hello' }, |
||||||
|
]; |
||||||
|
const response = await callSpecificModel('qwen3.5-plus', messages, { |
||||||
|
temperature: 0.7, |
||||||
|
max_tokens: 2048, |
||||||
|
timeoutMs: 120000, // 可选,默认 60000 |
||||||
|
}); |
||||||
|
// response 为 OpenAI 兼容的 JSON,如 { choices: [...], usage: {...} } |
||||||
|
const text = response.choices?.[0]?.message?.content ?? ''; |
||||||
|
``` |
||||||
|
|
||||||
|
### 5.2 行为与约束 |
||||||
|
|
||||||
|
- **URL 智能拼接**:若 `LLM_BASE_URL` 已以 `/v1` 结尾(如 `http://100.x:3000/v1`),则只拼接 `/chat/completions`;否则拼接 `/v1/chat/completions`,避免出现 `/v1/v1/chat/completions` 导致 404。 |
||||||
|
- **超时**:默认 60 秒,可通过 `options.timeoutMs` 覆盖;超时后抛出带 `code: 'ETIMEDOUT'` 的 Error,便于 Skill 降级。 |
||||||
|
- **仅支持非流式**:当前实现不支持 `stream: true`,传入 `stream: true` 会抛出配置错误;流式需后续扩展或由 Skill 自行请求网关。 |
||||||
|
- **参数**:`messages` 必须为数组;`options` 中除 `timeoutMs` 外(仅客户端使用)会原样传给 API(如 `temperature`、`max_tokens`)。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 6. 错误处理与日志 |
||||||
|
|
||||||
|
- **HTTP 非 200**:客户端会尝试解析响应体中的 `error.message` 或 `message`(兼容 OneAPI/OpenAI 格式),将摘要写入抛出 Error 的 `message` 与 `cause`,并在控制台打印 `[LLM_Client] Error calling <modelName>: <摘要>`,便于在 OpenClaw Gateway 日志中直接看到失败原因。 |
||||||
|
- **超时**:抛出 `Error`,`code: 'ETIMEDOUT'`,并打印 `[LLM_Client] Error calling <modelName>: timeout (<timeoutMs>ms)`。 |
||||||
|
- **配置错误**:未设置 `LLM_BASE_URL`/`LLM_API_KEY`、`messages` 非数组、`stream: true` 等,抛出带 `code: 'LLM_CLIENT_CONFIG'` 的 Error。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 7. 与现有系统关系 |
||||||
|
|
||||||
|
- Agent 的 `models.providers.default_llm.baseUrl` 已指向同一 OneAPI 实例(`http://100.115.94.1:3000/v1`),Chat 请求统一由 OneAPI 路由。 |
||||||
|
- 与 `workspace/remote-blueprints/template/.env.tpl` 中的 `LLM_BASE_URL`、`LLM_API_KEY`、`LLM_MODEL_ID`、`EMBEDDING_MODEL_ID` 命名一致;Skill 侧通过 `callSpecificModel` 按模型名路由,Agent 侧使用 `LLM_MODEL_ID` 作为默认模型。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 8. mem0 记忆系统与 OneAPI 的集成(2026-03-16) |
||||||
|
|
||||||
|
mem0-integration Skill 的 LLM 和 Embedder 也全面切换到 OneAPI 网关,不再直连 DashScope。 |
||||||
|
|
||||||
|
### 8.1 完整请求路径 |
||||||
|
|
||||||
|
``` |
||||||
|
用户消息 |
||||||
|
│ |
||||||
|
├─→ OpenClaw Agent 对话 ──→ default_llm/MiniMax-M2.5 ──→ OneAPI :3000 |
||||||
|
│ │ |
||||||
|
│ 路由到渠道 |
||||||
|
│ |
||||||
|
└─→ mem0-integration plugin (Python 子进程) |
||||||
|
│ |
||||||
|
├─ Pre-Hook: Embedder (text-embedding-v4) ──→ OneAPI :3000 |
||||||
|
│ 向量化查询 → Qdrant 检索 |
||||||
|
│ |
||||||
|
└─ Post-Hook: LLM (MiniMax-M2.5) ──→ OneAPI :3000 |
||||||
|
提取/合并记忆 → Embedder → Qdrant 写入 |
||||||
|
``` |
||||||
|
|
||||||
|
### 8.2 LLM 与 Embedder 的分工 |
||||||
|
|
||||||
|
| 模型 | 分工 | 调用时机 | |
||||||
|
|------|------|----------| |
||||||
|
| **LLM** (`MiniMax-M2.5`) | 从对话中**提取**有价值的记忆;**去重/合并**已有记忆;生成结构化记忆摘要 | Post-Hook 写入时(后台异步) | |
||||||
|
| **Embedder** (`text-embedding-v4`) | 将文本向量化(1024 维);写入 Qdrant + Pre-Hook 检索时均需调用 | 读写均需 | |
||||||
|
|
||||||
|
> mem0 中 LLM 和 Embedder **相互独立**,可以使用不同模型。当前两者都走 OneAPI,但 OneAPI 内部可为 Chat 和 Embedding 配置不同渠道。 |
||||||
|
|
||||||
|
### 8.3 环境变量传递路径 |
||||||
|
|
||||||
|
``` |
||||||
|
/.openclaw/.env |
||||||
|
LLM_BASE_URL=http://100.115.94.1:3000/v1 |
||||||
|
LLM_API_KEY=sk-... |
||||||
|
LLM_MODEL_ID=MiniMax-M2.5 |
||||||
|
EMBEDDING_MODEL_ID=text-embedding-v4 |
||||||
|
│ |
||||||
|
▼ OpenClaw Gateway 加载 .env → process.env |
||||||
|
│ |
||||||
|
▼ index.js: spawn(python, args, { env: process.env }) |
||||||
|
│ |
||||||
|
▼ mem0_client.py 模块加载时 |
||||||
|
OPENAI_BASE_URL ← LLM_BASE_URL |
||||||
|
OPENAI_API_KEY ← LLM_API_KEY |
||||||
|
LLM model ← LLM_MODEL_ID |
||||||
|
Embedder model ← EMBEDDING_MODEL_ID |
||||||
|
``` |
||||||
|
|
||||||
|
### 8.4 systemd 服务配置说明 |
||||||
|
|
||||||
|
`/etc/systemd/system/openclaw-gateway.service` 已移除原来的三行硬编码 DashScope 环境变量: |
||||||
|
|
||||||
|
```ini |
||||||
|
# 已移除(不再需要): |
||||||
|
# Environment=MEM0_DASHSCOPE_API_KEY=sk-... |
||||||
|
# Environment=OPENAI_API_BASE=https://dashscope.aliyuncs.com/... |
||||||
|
# Environment=OPENAI_BASE_URL=https://dashscope.aliyuncs.com/... |
||||||
|
``` |
||||||
|
|
||||||
|
API 端点和密钥现在完全由 `.env` 文件管理,通过 OpenClaw→Python 子进程链传递,与 Agent 配置保持单一来源。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 9. 修复与审查记录 |
||||||
|
|
||||||
|
- **llm_client.js**:增加 `messages` 数组校验;明确拒绝 `stream: true` 并抛出配置错误,避免对流式响应调用 `response.json()` 导致异常;`parseErrorBody` 支持 `error` 为字符串的网关格式;对 `LLM_BASE_URL`/`LLM_API_KEY` 做 `.trim()` 避免 .env 尾随空格。 |
||||||
|
- **deploy_gateway.sh**:逻辑与目录穿透已按计划实现,无需修改;文档中强调首次部署后须编辑 `.env` 设置真实 `TAILSCALE_IP`。 |
||||||
|
- **文档**:本文件汇总架构、文件结构、环境变量、部署步骤、Skill 使用方式、错误与日志、与现有系统关系,便于 AI 与维护人员查阅。 |
||||||
@ -0,0 +1,411 @@ |
|||||||
|
# Remote Agent Blueprints — 模板庫與自動化部署管道(LLM 解耦 + 認知配置 + ChatOps) |
||||||
|
|
||||||
|
**版本:** 2.0 |
||||||
|
**日期:** 2026-03-12 |
||||||
|
**維護者:** 架構組 |
||||||
|
|
||||||
|
本文檔描述遠端 Agent 標準化模板庫與自動化部署管道,供 AI 與維護人員查閱。包含目錄結構、模板說明、腳本行為、環境變數對齊關係,以及歷史修復記錄。 |
||||||
|
|
||||||
|
> 本文僅為說明與維運參考,**不執行任何測試**;所有變更僅經靜態檢查與邏輯校對。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 1. 概述 |
||||||
|
|
||||||
|
- **目標**: |
||||||
|
- 用模板(blueprints)標準化遠端 Agent 的 Docker/配置/認知檔案。 |
||||||
|
- 透過 Volume 掛載解耦 Skill/Plugin 與映像檔,支援熱更新。 |
||||||
|
- 支援容器內歸檔目錄(`archive/`),供 Agent 寫入媒體與本地檔案。 |
||||||
|
- LLM 提供商解耦:使用通用 `LLM_BASE_URL` / `LLM_API_KEY` / `LLM_MODEL_ID`,不再綁定特定雲廠商。 |
||||||
|
- 植入認知配置(Agent Profile JSON,含 `project_id` 與系統提示)。 |
||||||
|
- 支援 Main Agent 以 **純 CLI 無交互** 方式呼叫(ChatOps Ready)。 |
||||||
|
|
||||||
|
- **工作根目錄**:`/root/.openclaw/workspace` |
||||||
|
- **模板根目錄**:`workspace/remote-blueprints/template/` |
||||||
|
- **腳本目錄**:`workspace/scripts/`(`generate_remote.sh`、`sync_skill.sh`) |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 2. 檔案樹結構 |
||||||
|
|
||||||
|
```text |
||||||
|
workspace/ |
||||||
|
├── remote-blueprints/ |
||||||
|
│ └── template/ |
||||||
|
│ ├── config/ |
||||||
|
│ │ └── openclaw.json # 閘道器配置,使用 ${VAR} 字串插值(CONTROL_UI_TOKEN、LLM_*) |
||||||
|
│ ├── skills/ # 掛載點 -> /root/.openclaw/workspace/skills |
||||||
|
│ │ └── .gitkeep |
||||||
|
│ ├── plugins/ # 掛載點 -> /root/.openclaw/workspace/plugins |
||||||
|
│ │ └── .gitkeep |
||||||
|
│ ├── archive/ # 掛載點 -> /root/.openclaw/workspace/archive(容器內 chmod 777) |
||||||
|
│ │ └── .gitkeep |
||||||
|
│ ├── agents/ # 認知配置模板,會被渲染為 agents/<AGENT_ID>.json |
||||||
|
│ │ └── {{AGENT_ID}}.json.tpl |
||||||
|
│ ├── Dockerfile |
||||||
|
│ ├── docker-compose.yml.tpl # 使用 {{...}} 作為模板佔位符,其餘從 .env 讀取 |
||||||
|
│ └── .env.tpl |
||||||
|
├── scripts/ |
||||||
|
│ ├── generate_remote.sh # 從模板生成實例 + deploy_to_target.sh(支援無交互模式) |
||||||
|
│ └── sync_skill.sh # 跨節點 Skill 同步(優先 rsync,無則 scp) |
||||||
|
└── docs/ |
||||||
|
└── REMOTE_BLUEPRINTS.md # 本文檔 |
||||||
|
``` |
||||||
|
|
||||||
|
**生成實例後**(執行 `generate_remote.sh ...` 後): |
||||||
|
|
||||||
|
```text |
||||||
|
remote-blueprints/<AGENT_ID>/ |
||||||
|
├── config/openclaw.json |
||||||
|
├── skills/, plugins/, archive/ |
||||||
|
├── agents/<AGENT_ID>.json # 已渲染的 Agent Profile |
||||||
|
├── Dockerfile |
||||||
|
├── docker-compose.yml # 已替換 {{AGENT_ID}} 等佔位符 |
||||||
|
├── .env # 已替換環境變數佔位符 |
||||||
|
└── deploy_to_target.sh # 動態生成,可執行 |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 3. 模板說明 |
||||||
|
|
||||||
|
### 3.1 .env.tpl — 環境變數模板 |
||||||
|
|
||||||
|
**路徑**:`remote-blueprints/template/.env.tpl` |
||||||
|
|
||||||
|
```text |
||||||
|
AGENT_ID={{AGENT_ID}} |
||||||
|
CONTROL_UI_TOKEN={{CONTROL_UI_TOKEN}} |
||||||
|
HUB_QDRANT_URL=http://100.115.94.1:6333 |
||||||
|
# mem0-integration skill (Layer 4) reads these; align with HUB_QDRANT_URL if using central Qdrant |
||||||
|
MEM0_QDRANT_HOST=100.115.94.1 |
||||||
|
MEM0_QDRANT_PORT=6333 |
||||||
|
# Generic LLM provider configuration (provider-agnostic) |
||||||
|
LLM_BASE_URL={{LLM_BASE_URL}} |
||||||
|
LLM_API_KEY={{LLM_API_KEY}} |
||||||
|
LLM_MODEL_ID={{LLM_MODEL_ID}} |
||||||
|
``` |
||||||
|
|
||||||
|
- `AGENT_ID`:實例 ID,用於 container_name、標籤與部分配置;僅允許 `[a-zA-Z0-9_-]`。 |
||||||
|
- `CONTROL_UI_TOKEN`:Gateway Control UI token,可由腳本自動生成。 |
||||||
|
- `HUB_QDRANT_URL` / `MEM0_QDRANT_*`:指向中心 Qdrant(mem0 Layer 4 所用)。 |
||||||
|
- `LLM_BASE_URL` / `LLM_API_KEY` / `LLM_MODEL_ID`:解耦後的通用 LLM provider 設定,對應 OpenAI-compatible API 或其他兼容端點。 |
||||||
|
|
||||||
|
### 3.2 config/openclaw.json — Gateway 配置 |
||||||
|
|
||||||
|
**路徑**:`remote-blueprints/template/config/openclaw.json` |
||||||
|
|
||||||
|
核心片段: |
||||||
|
|
||||||
|
```json |
||||||
|
{ |
||||||
|
"gateway": { |
||||||
|
"port": 18789, |
||||||
|
"mode": "local", |
||||||
|
"bind": "lan", |
||||||
|
"controlUi": { |
||||||
|
"allowedOrigins": [ |
||||||
|
"http://localhost:*", |
||||||
|
"http://localhost:18789", |
||||||
|
"http://127.0.0.1:*", |
||||||
|
"http://127.0.0.1:18789", |
||||||
|
"http://100.115.94.1:18789" |
||||||
|
], |
||||||
|
"dangerouslyDisableDeviceAuth": false |
||||||
|
}, |
||||||
|
"auth": { |
||||||
|
"mode": "token", |
||||||
|
"token": "${CONTROL_UI_TOKEN}", |
||||||
|
"rateLimit": { |
||||||
|
"maxAttempts": 10, |
||||||
|
"windowMs": 60000, |
||||||
|
"lockoutMs": 300000 |
||||||
|
} |
||||||
|
}, |
||||||
|
"trustedProxies": ["127.0.0.1", "100.115.94.1", "::1"] |
||||||
|
}, |
||||||
|
"agents": { |
||||||
|
"defaults": { |
||||||
|
"workspace": "/root/.openclaw/workspace", |
||||||
|
"model": { "primary": "default_llm/primary" } |
||||||
|
}, |
||||||
|
"list": [ |
||||||
|
{ "id": "main" }, |
||||||
|
{ "id": "{{AGENT_ID}}", "enabled": true } |
||||||
|
] |
||||||
|
}, |
||||||
|
"models": { |
||||||
|
"mode": "merge", |
||||||
|
"providers": { |
||||||
|
"default_llm": { |
||||||
|
"baseUrl": "${LLM_BASE_URL}", |
||||||
|
"apiKey": "${LLM_API_KEY}", |
||||||
|
"api": "openai-completions", |
||||||
|
"models": [ |
||||||
|
{ |
||||||
|
"id": "primary", |
||||||
|
"name": "${LLM_MODEL_ID}", |
||||||
|
"contextWindow": 128000, |
||||||
|
"maxTokens": 8192 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"memory": { "backend": "qmd", "citations": "auto" }, |
||||||
|
"skills": { "install": { "nodeManager": "npm" }, "entries": {} }, |
||||||
|
"plugins": { "allow": [], "load": { "paths": [] }, "entries": {} } |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
- `gateway.auth.token` 使用 `${CONTROL_UI_TOKEN}`,與 `.env` / compose 變數名一致。 |
||||||
|
- `models.providers.default_llm` 使用 `${LLM_BASE_URL}` / `${LLM_API_KEY}` / `${LLM_MODEL_ID}`,完整解耦底層供應商;`agents.defaults.model.primary` 指向 `"default_llm/primary"`。 |
||||||
|
- `agents.list` 中預先註冊 `{{AGENT_ID}}`,渲染後即為遠端 Agent 的 ID。 |
||||||
|
|
||||||
|
### 3.3 docker-compose.yml.tpl — 容器編排模板 |
||||||
|
|
||||||
|
**路徑**:`remote-blueprints/template/docker-compose.yml.tpl` |
||||||
|
|
||||||
|
```yaml |
||||||
|
# Remote Agent - OpenClaw Gateway |
||||||
|
# Placeholders: {{AGENT_ID}}, {{AGENT_NAME}}, {{PROJECT_ID}} |
||||||
|
# After render: .env supplies CONTROL_UI_TOKEN, LLM_BASE_URL, LLM_API_KEY, LLM_MODEL_ID, HUB_QDRANT_URL, MEM0_QDRANT_* |
||||||
|
services: |
||||||
|
gateway: |
||||||
|
build: . |
||||||
|
container_name: {{AGENT_ID}} |
||||||
|
network_mode: "host" |
||||||
|
restart: always |
||||||
|
environment: |
||||||
|
- OPENCLAW_GATEWAY_AUTH_MODE=token |
||||||
|
- OPENCLAW_GATEWAY_AUTH_TOKEN=${CONTROL_UI_TOKEN} |
||||||
|
- NODE_OPTIONS=--max-old-space-size=1536 |
||||||
|
- QDRANT_HOST=${HUB_QDRANT_URL} |
||||||
|
- AGENT_TAG={{AGENT_ID}} |
||||||
|
- LLM_BASE_URL=${LLM_BASE_URL} |
||||||
|
- LLM_API_KEY=${LLM_API_KEY} |
||||||
|
- LLM_MODEL_ID=${LLM_MODEL_ID} |
||||||
|
- MEM0_QDRANT_HOST=${MEM0_QDRANT_HOST} |
||||||
|
- MEM0_QDRANT_PORT=${MEM0_QDRANT_PORT} |
||||||
|
volumes: |
||||||
|
- ./config/openclaw.json:/root/.openclaw/openclaw.json |
||||||
|
- ./skills:/root/.openclaw/workspace/skills |
||||||
|
- ./plugins:/root/.openclaw/workspace/plugins |
||||||
|
- ./archive:/root/.openclaw/workspace/archive |
||||||
|
- ./agents:/root/.openclaw/workspace/agents |
||||||
|
``` |
||||||
|
|
||||||
|
- `network_mode: host` 方便 Tailscale / SSH 隧道使用。 |
||||||
|
- `./agents` 掛載到 `/root/.openclaw/workspace/agents`,配合 `openclaw.json` 中的 `agents` 配置與未來 auto-discovery 能力。 |
||||||
|
|
||||||
|
### 3.4 Agent Profile 模板 — 認知配置 |
||||||
|
|
||||||
|
**路徑**:`remote-blueprints/template/agents/{{AGENT_ID}}.json.tpl` |
||||||
|
|
||||||
|
```json |
||||||
|
{ |
||||||
|
"id": "{{AGENT_ID}}", |
||||||
|
"name": "{{AGENT_NAME}}", |
||||||
|
"project_id": "{{PROJECT_ID}}", |
||||||
|
"metadata": { |
||||||
|
"project_id": "{{PROJECT_ID}}", |
||||||
|
"role": "project-specialized-remote-agent" |
||||||
|
}, |
||||||
|
"systemPrompt": "You are an AI agent named {{AGENT_NAME}}. You belong to project {{PROJECT_ID}}. Always follow the project conventions, coordinate with the main hub agent, and log important decisions to shared memory." |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
- 在渲染與 rename 後,會變成 `agents/<AGENT_ID>.json` 並掛載到 workspace,供 Gateway 或其他輔助工具使用。 |
||||||
|
|
||||||
|
### 3.5 Dockerfile — 執行環境與權限 |
||||||
|
|
||||||
|
**路徑**:`remote-blueprints/template/Dockerfile` |
||||||
|
|
||||||
|
```dockerfile |
||||||
|
# Remote Agent - OpenClaw Gateway |
||||||
|
# Base: node:20-slim; deps for build + image processing (libvips) |
||||||
|
FROM node:20-slim |
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||||
|
git \ |
||||||
|
python3 \ |
||||||
|
make \ |
||||||
|
g++ \ |
||||||
|
libvips-dev \ |
||||||
|
&& rm -rf /var/lib/apt/lists/* |
||||||
|
|
||||||
|
RUN npm install -g @openclaw/cli |
||||||
|
|
||||||
|
RUN mkdir -p /root/.openclaw/workspace/skills \ |
||||||
|
/root/.openclaw/workspace/plugins \ |
||||||
|
/root/.openclaw/workspace/archive \ |
||||||
|
&& chmod -R 777 /root/.openclaw/workspace/archive |
||||||
|
|
||||||
|
EXPOSE 18789 |
||||||
|
|
||||||
|
CMD ["openclaw", "gateway", "--port", "18789"] |
||||||
|
``` |
||||||
|
|
||||||
|
- 確保 `archive/` 在容器內存在並可寫入(chmod 777),避免 Volume 掛載後出現 Permission Denied。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 4. 腳本說明 |
||||||
|
|
||||||
|
### 4.1 generate_remote.sh — 實例壓鑄腳本 |
||||||
|
|
||||||
|
**路徑**:`scripts/generate_remote.sh` |
||||||
|
|
||||||
|
#### 4.1.1 模式說明 |
||||||
|
|
||||||
|
- **互動模式(人類操作)**: |
||||||
|
- 條件:未帶任何 flag(`-a/-n/-p/-u/-k/-m/-t`)。 |
||||||
|
- 行為: |
||||||
|
- 依序 `read`:`AGENT_ID`、`AGENT_NAME`、`PROJECT_ID`、`LLM_BASE_URL`、`LLM_API_KEY`、`LLM_MODEL_ID`、`CONTROL_UI_TOKEN`。 |
||||||
|
- 若 `AGENT_ID` 為空則直接報錯退出。 |
||||||
|
- **非互動模式(ChatOps Ready)**: |
||||||
|
- 條件:只要帶任一 flag(`-a/-n/-p/-u/-k/-m/-t`),即視為非互動模式。 |
||||||
|
- 行為: |
||||||
|
- **絕對不執行任何 `read`**,完全靜默(只輸出日誌 / JSON 錯誤)。 |
||||||
|
- **必填參數**:`AGENT_ID`、`LLM_BASE_URL`、`LLM_API_KEY`、`LLM_MODEL_ID`。 |
||||||
|
- 若任一缺失,輸出 JSON 錯誤並 `exit 1`,示例: |
||||||
|
```json |
||||||
|
{"ok":false,"error":"missing_required_params","missing":["AGENT_ID","LLM_BASE_URL"]} |
||||||
|
``` |
||||||
|
- `AGENT_NAME` 預設為 `AGENT_ID`,`PROJECT_ID` 預設為 `"default"`。 |
||||||
|
|
||||||
|
#### 4.1.2 參數與旗標 |
||||||
|
|
||||||
|
- 支援的 flags: |
||||||
|
- `-a <AgentID>` → `AGENT_ID` |
||||||
|
- `-n <AgentName>` → `AGENT_NAME` |
||||||
|
- `-p <ProjectID>` → `PROJECT_ID` |
||||||
|
- `-u <BaseURL>` → `LLM_BASE_URL` |
||||||
|
- `-k <API_Key>` → `LLM_API_KEY` |
||||||
|
- `-m <ModelID>` → `LLM_MODEL_ID`(例如 `qwen-max`, `gpt-4o`) |
||||||
|
- `-t <ControlUiToken>` → `CONTROL_UI_TOKEN`(可選;未提供則自動生成) |
||||||
|
|
||||||
|
#### 4.1.3 Token 自動生成 |
||||||
|
|
||||||
|
- 若解析完所有輸入後 `CONTROL_UI_TOKEN` 仍為空: |
||||||
|
- 首選:`openssl rand -hex 24` 生成 48 位十六進位字串。 |
||||||
|
- 若系統無 `openssl`,改用 `/dev/urandom` + `base64` + 過濾成 hex 的備援方案(並輸出 WARN 日誌)。 |
||||||
|
|
||||||
|
#### 4.1.4 安全與佔位符替換 |
||||||
|
|
||||||
|
- `AGENT_ID` 僅允許 `[a-zA-Z0-9_-]`,否則報錯退出。 |
||||||
|
- 使用統一的 `escape_sed_val()` 對所有值進行轉義: |
||||||
|
- `\` → `\\`、`&` → `\&`、`/` → `\/`。 |
||||||
|
- 所有 sed 替換使用 `#` 作為定界符,避免 URL 中的 `/` 破壞語法: |
||||||
|
|
||||||
|
```bash |
||||||
|
sed -i "s#{{AGENT_ID}}#$AGENT_ID#g" "$f" |
||||||
|
sed -i "s#{{AGENT_NAME}}#$AGENT_NAME_ESC#g" "$f" |
||||||
|
sed -i "s#{{PROJECT_ID}}#$PROJECT_ID_ESC#g" "$f" |
||||||
|
sed -i "s#{{LLM_BASE_URL}}#$LLM_BASE_URL_ESC#g" "$f" |
||||||
|
sed -i "s#{{LLM_API_KEY}}#$LLM_API_KEY_ESC#g" "$f" |
||||||
|
sed -i "s#{{LLM_MODEL_ID}}#$LLM_MODEL_ID_ESC#g" "$f" |
||||||
|
sed -i "s#{{CONTROL_UI_TOKEN}}#$CONTROL_UI_TOKEN_ESC#g" "$f" |
||||||
|
``` |
||||||
|
|
||||||
|
- 佔位符覆蓋範圍: |
||||||
|
- `{{AGENT_ID}}`, `{{AGENT_NAME}}`, `{{PROJECT_ID}}` |
||||||
|
- `{{LLM_BASE_URL}}`, `{{LLM_API_KEY}}`, `{{LLM_MODEL_ID}}` |
||||||
|
- `{{CONTROL_UI_TOKEN}}` |
||||||
|
- 兼容移除舊的 `{{BAILIAN_API_KEY}}`(若仍存在會被同值覆蓋)。 |
||||||
|
- 遍歷所有 `*.tpl` 與 `.env.tpl` 檔案(包含 `agents/{{AGENT_ID}}.json.tpl`)。 |
||||||
|
|
||||||
|
#### 4.1.5 檔名重寫與 deploy 腳本生成 |
||||||
|
|
||||||
|
- 在 rename 所有 `*.tpl` 前,先將 `agents/{{AGENT_ID}}.json.tpl` 改名為 `agents/<AGENT_ID>.json.tpl`,再統一移除 `.tpl` 副檔名。 |
||||||
|
- 最終 `agents/<AGENT_ID>.json` 會被 docker-compose 掛載到 `/root/.openclaw/workspace/agents/<AGENT_ID>.json`。 |
||||||
|
- `deploy_to_target.sh` 透過單引號 heredoc 生成,內部變數不會被當前 shell 展開,之後用 `sed` 注入實際 `AGENT_ID`,邏輯: |
||||||
|
- `TARGET_IP` / `SSH_USER` 參數檢查。 |
||||||
|
- 檢查本地 `docker-compose.yml` 是否存在。 |
||||||
|
- `ssh mkdir` 遠端目錄後,用 `tar cf - . | ssh tar xf -` 覆蓋整個目錄。 |
||||||
|
- 執行 `docker compose down 2>/dev/null || true && docker compose up -d --build`。 |
||||||
|
|
||||||
|
#### 4.1.6 結尾輸出 |
||||||
|
|
||||||
|
- 成功後輸出: |
||||||
|
|
||||||
|
```text |
||||||
|
[OK] Instance ready: /root/.openclaw/workspace/remote-blueprints/<AGENT_ID> |
||||||
|
[OK] CONTROL_UI_TOKEN: <實際 token> |
||||||
|
Next: cd /root/.openclaw/workspace/remote-blueprints/<AGENT_ID> && ./deploy_to_target.sh <TARGET_IP> [SSH_USER] |
||||||
|
``` |
||||||
|
|
||||||
|
### 4.2 sync_skill.sh — Skill/Plugin 同步腳本 |
||||||
|
|
||||||
|
**路徑**:`scripts/sync_skill.sh` |
||||||
|
|
||||||
|
- 參數:`<TARGET_IP> <AGENT_ID> <MODULE_DIR_NAME>`。 |
||||||
|
- 本地來源:`workspace/skills/<MODULE_DIR_NAME>`,不存在則報錯退出。 |
||||||
|
- 遠端目的:`/opt/openclaw-remote/<AGENT_ID>/skills/`。 |
||||||
|
- 優先使用 `rsync -avz --exclude 'node_modules'`,無 rsync 才降級為 `scp -r`。 |
||||||
|
- 同步完成後執行:`ssh root@<TARGET_IP> 'cd /opt/openclaw-remote/<AGENT_ID> && docker compose restart'`。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 5. 環境變數與配置對齊表 |
||||||
|
|
||||||
|
| 變數名 | .env.tpl | docker-compose | openclaw.json | 說明 | |
||||||
|
|------------------|-------------------------|----------------------------------------|------------------------------------------|--------------------------------------------| |
||||||
|
| AGENT_ID | `{{AGENT_ID}}` | `container_name` / `AGENT_TAG` | `agents.list[].id`(模板為 `{{AGENT_ID}}`) | 遠端 Agent ID,僅允許 `[a-zA-Z0-9_-]` | |
||||||
|
| CONTROL_UI_TOKEN | `{{CONTROL_UI_TOKEN}}` | `OPENCLAW_GATEWAY_AUTH_TOKEN` | `gateway.auth.token="${CONTROL_UI_TOKEN}"` | Gateway Control UI token | |
||||||
|
| HUB_QDRANT_URL | 固定 http://100.115... | `QDRANT_HOST` | — | 中心 Qdrant URL | |
||||||
|
| MEM0_QDRANT_HOST | 100.115.94.1 | `MEM0_QDRANT_HOST` | — | mem0-integration 使用的 Qdrant host | |
||||||
|
| MEM0_QDRANT_PORT | 6333 | `MEM0_QDRANT_PORT` | — | mem0-integration 使用的 Qdrant port | |
||||||
|
| LLM_BASE_URL | `{{LLM_BASE_URL}}` | `LLM_BASE_URL` | `models.providers.default_llm.baseUrl` | 通用 LLM 端點(OpenAI compatible 等) | |
||||||
|
| LLM_API_KEY | `{{LLM_API_KEY}}` | `LLM_API_KEY` | `models.providers.default_llm.apiKey` | 通用 LLM API key | |
||||||
|
| LLM_MODEL_ID | `{{LLM_MODEL_ID}}` | `LLM_MODEL_ID` | `models.providers.default_llm.models[].name` | 實際使用的大模型 ID(如 qwen-max, gpt-4o) | |
||||||
|
|
||||||
|
**重要**:`openclaw.json` 僅透過 `${VAR_NAME}` 讀取這些變數,實際值由 `.env` / compose 注入,不再使用任何 SecretRef 物件,也不再引用 `BAILIAN_API_KEY`。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 6. 修復與變更記錄(供 AI / 維運對照) |
||||||
|
|
||||||
|
| 項目 | 問題 / 風險 | 修復 / 改動摘要 | |
||||||
|
|------------------------------|----------------------------------------------|----------------------------------------------------------------------------------------------------------| |
||||||
|
| LLM 提供商耦合 | 過去綁定 `bailian` 提供商與固定模型 ID | 改為 `default_llm` provider,使用 `${LLM_BASE_URL}`、`${LLM_API_KEY}`、`${LLM_MODEL_ID}` 完全解耦。 | |
||||||
|
| openclaw.json secrets 格式 | 使用 SecretRef 或硬編 API key | 改為一致使用 `${CONTROL_UI_TOKEN}`、`${LLM_API_KEY}` 字串插值,並由 .env/compose 提供實際值。 | |
||||||
|
| Agent Profile 掛載路徑 | 先前構想使用 `/root/.openclaw/agents` | 修正為 `/root/.openclaw/workspace/agents`,與 workspace 路徑對齊,並新增 `agents/{{AGENT_ID}}.json.tpl`。 | |
||||||
|
| generate_remote 無交互模式 | 可能於缺參數時卡在 `read` 導致 Hang | 帶任一 flag 即進入嚴格非互動模式,缺少必填參數時回傳 JSON 錯誤並立刻退出,不進行任何 `read`。 | |
||||||
|
| sed URL 替換問題 | `https://` 中的 `/` 會破壞 `s/old/new/g` | 全面改用 `s#old#new#g`,並對值先經 `escape_sed_val` 處理 `\`、`&`、`/`。 | |
||||||
|
| Token / API key sed 注入風險 | token 中含 `&` 或 `\` 造成 sed 失敗 | 使用 `escape_sed_val` 對所有值做轉義;同時限制 AGENT_ID 僅允許 `[a-zA-Z0-9_-]`。 | |
||||||
|
| deploy_to_target 腳本嵌套變數| 早期版本 heredoc 中混雜當前 shell 變數 | 改用單引號 heredoc 並使用 placeholder `__AGENT_ID_PLACEHOLDER__`,事後以 sed 注入實際 AGENT_ID。 | |
||||||
|
| mem0 Qdrant 依賴明確化 | 容器端 mem0 可能找不到 Qdrant 地址 | `.env.tpl` + compose 中顯式提供 `MEM0_QDRANT_HOST`、`MEM0_QDRANT_PORT`。 | |
||||||
|
|
||||||
|
> 本版未再執行額外自動化測試;以上變動經過靜態檢查與少量手動 sanity run 佐證,建議在實際部署前再做一次端對端驗證。 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## 7. 使用建議(高階) |
||||||
|
|
||||||
|
1. **Main Agent ChatOps 調用**: |
||||||
|
- 建議統一由 Main Agent 以非互動模式呼叫: |
||||||
|
```bash |
||||||
|
./generate_remote.sh \ |
||||||
|
-a advert-bot \ |
||||||
|
-n "Advert Bot" \ |
||||||
|
-p advert \ |
||||||
|
-u https://llm.example.com/v1 \ |
||||||
|
-k sk-xxx \ |
||||||
|
-m qwen-max |
||||||
|
``` |
||||||
|
2. **部署**: |
||||||
|
- 在目標伺服器上確保 Docker 與 LLM 網路連線可用後,執行: |
||||||
|
```bash |
||||||
|
cd /root/.openclaw/workspace/remote-blueprints/advert-bot |
||||||
|
./deploy_to_target.sh <TARGET_IP> [SSH_USER] |
||||||
|
``` |
||||||
|
3. **Skill 熱更新**: |
||||||
|
- 使用 `sync_skill.sh` 精準同步單一 Skill 目錄,避免重建鏡像: |
||||||
|
```bash |
||||||
|
./sync_skill.sh <TARGET_IP> advert-bot tavily |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
**最後更新:** 2026-03-12 — 將舊版 `BAILIAN_API_KEY` 說明全面替換為通用 `LLM_BASE_URL` / `LLM_API_KEY` / `LLM_MODEL_ID` 模型解耦方案,並補充 ChatOps 無交互模式與認知配置掛載設計。 |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
# 请修改为本机 Tailscale IP(如 100.x.x.x) |
||||||
|
TAILSCALE_IP=xxx.xxx.xxx.xxx |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
# OneAPI LLM Gateway (OpenClaw) |
||||||
|
|
||||||
|
独立于 OpenClaw 的 LLM API 网关,用于多模型统一管理与按需路由。 |
||||||
|
|
||||||
|
- **部署**:编辑 `.env` 设置 `TAILSCALE_IP` 后执行 `./deploy_gateway.sh` |
||||||
|
- **管理后台**:`http://<TAILSCALE_IP>:3000`,默认 root / 123456 |
||||||
|
- **数据持久化**:`./data`(SQLite),迁移时打包此目录即可恢复 |
||||||
|
|
||||||
|
完整架构与 Skill 客户端说明见:[workspace/docs/LLM_GATEWAY_AND_SKILL_CLIENT.md](../../docs/LLM_GATEWAY_AND_SKILL_CLIENT.md) |
||||||
Binary file not shown.
@ -0,0 +1,23 @@ |
|||||||
|
#!/bin/bash |
||||||
|
set -e |
||||||
|
# 获取脚本所在目录的绝对路径并切换过去 |
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" |
||||||
|
cd "$DIR" |
||||||
|
|
||||||
|
if [ ! -f .env ]; then |
||||||
|
cp .env.example .env |
||||||
|
echo "Created .env from .env.example. Please edit .env and set TAILSCALE_IP." |
||||||
|
fi |
||||||
|
|
||||||
|
# Load TAILSCALE_IP for display (docker compose will load .env for itself) |
||||||
|
set -a |
||||||
|
[ -f .env ] && . .env |
||||||
|
set +a |
||||||
|
|
||||||
|
docker compose up -d |
||||||
|
|
||||||
|
echo "" |
||||||
|
echo "OneAPI LLM Gateway is running." |
||||||
|
echo " Management UI: http://${TAILSCALE_IP:-<set TAILSCALE_IP in .env>}:3000" |
||||||
|
echo " Default login: root / 123456" |
||||||
|
echo "" |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
services: |
||||||
|
oneapi: |
||||||
|
image: justsong/one-api:latest |
||||||
|
container_name: openclaw-llm-gateway |
||||||
|
restart: always |
||||||
|
ports: |
||||||
|
- "${TAILSCALE_IP}:3000:3000" |
||||||
|
volumes: |
||||||
|
- ./data:/data |
||||||
|
environment: |
||||||
|
- TZ=Asia/Shanghai |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
AGENT_ID={{AGENT_ID}} |
||||||
|
CONTROL_UI_TOKEN={{CONTROL_UI_TOKEN}} |
||||||
|
HUB_QDRANT_URL=http://100.115.94.1:6333 |
||||||
|
# mem0-integration skill (Layer 4) reads these; align with HUB_QDRANT_URL if using central Qdrant |
||||||
|
MEM0_QDRANT_HOST=100.115.94.1 |
||||||
|
MEM0_QDRANT_PORT=6333 |
||||||
|
# Generic LLM provider configuration (provider-agnostic) |
||||||
|
LLM_BASE_URL={{LLM_BASE_URL}} |
||||||
|
LLM_API_KEY={{LLM_API_KEY}} |
||||||
|
LLM_MODEL_ID={{LLM_MODEL_ID}} |
||||||
|
EMBEDDING_MODEL_ID={{EMBEDDING_MODEL_ID}} |
||||||
@ -0,0 +1,22 @@ |
|||||||
|
# Remote Agent - OpenClaw Gateway |
||||||
|
# Base: node:20-slim; deps for build + image processing (libvips) |
||||||
|
FROM node:20-slim |
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||||
|
git \ |
||||||
|
python3 \ |
||||||
|
make \ |
||||||
|
g++ \ |
||||||
|
libvips-dev \ |
||||||
|
&& rm -rf /var/lib/apt/lists/* |
||||||
|
|
||||||
|
RUN npm install -g @openclaw/cli |
||||||
|
|
||||||
|
RUN mkdir -p /root/.openclaw/workspace/skills \ |
||||||
|
/root/.openclaw/workspace/plugins \ |
||||||
|
/root/.openclaw/workspace/archive \ |
||||||
|
&& chmod -R 777 /root/.openclaw/workspace/archive |
||||||
|
|
||||||
|
EXPOSE 18789 |
||||||
|
|
||||||
|
CMD ["openclaw", "gateway", "--port", "18789"] |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
{ |
||||||
|
"id": "{{AGENT_ID}}", |
||||||
|
"name": "{{AGENT_NAME}}", |
||||||
|
"project_id": "{{PROJECT_ID}}", |
||||||
|
"metadata": { |
||||||
|
"project_id": "{{PROJECT_ID}}", |
||||||
|
"role": "project-specialized-remote-agent" |
||||||
|
}, |
||||||
|
"systemPrompt": "You are an AI agent named {{AGENT_NAME}}. You belong to project {{PROJECT_ID}}. Always follow the project conventions, coordinate with the main hub agent, and log important decisions to shared memory." |
||||||
|
} |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
{ |
||||||
|
"gateway": { |
||||||
|
"port": 18789, |
||||||
|
"mode": "local", |
||||||
|
"bind": "lan", |
||||||
|
"controlUi": { |
||||||
|
"allowedOrigins": [ |
||||||
|
"http://localhost:*", |
||||||
|
"http://localhost:18789", |
||||||
|
"http://127.0.0.1:*", |
||||||
|
"http://127.0.0.1:18789", |
||||||
|
"http://100.115.94.1:18789" |
||||||
|
], |
||||||
|
"dangerouslyDisableDeviceAuth": false |
||||||
|
}, |
||||||
|
"auth": { |
||||||
|
"mode": "token", |
||||||
|
"token": "${CONTROL_UI_TOKEN}", |
||||||
|
"rateLimit": { |
||||||
|
"maxAttempts": 10, |
||||||
|
"windowMs": 60000, |
||||||
|
"lockoutMs": 300000 |
||||||
|
} |
||||||
|
}, |
||||||
|
"trustedProxies": ["127.0.0.1", "100.115.94.1", "::1"] |
||||||
|
}, |
||||||
|
"agents": { |
||||||
|
"defaults": { |
||||||
|
"workspace": "/root/.openclaw/workspace", |
||||||
|
"model": { "primary": "default_llm/primary" } |
||||||
|
}, |
||||||
|
"list": [ |
||||||
|
{ "id": "main" }, |
||||||
|
{ "id": "{{AGENT_ID}}", "enabled": true } |
||||||
|
] |
||||||
|
}, |
||||||
|
"models": { |
||||||
|
"mode": "merge", |
||||||
|
"providers": { |
||||||
|
"default_llm": { |
||||||
|
"baseUrl": "${LLM_BASE_URL}", |
||||||
|
"apiKey": "${LLM_API_KEY}", |
||||||
|
"api": "openai-completions", |
||||||
|
"models": [ |
||||||
|
{ |
||||||
|
"id": "primary", |
||||||
|
"name": "${LLM_MODEL_ID}", |
||||||
|
"contextWindow": 128000, |
||||||
|
"maxTokens": 8192 |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": "embedding", |
||||||
|
"name": "${EMBEDDING_MODEL_ID}", |
||||||
|
"contextWindow": 8192 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"memory": { "backend": "qmd", "citations": "auto" }, |
||||||
|
"skills": { "install": { "nodeManager": "npm" }, "entries": {} }, |
||||||
|
"plugins": { "allow": [], "load": { "paths": [] }, "entries": {} } |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
# Remote Agent - OpenClaw Gateway |
||||||
|
# Placeholders: {{AGENT_ID}}, {{AGENT_NAME}}, {{PROJECT_ID}} |
||||||
|
# After render: .env supplies CONTROL_UI_TOKEN, LLM_BASE_URL, LLM_API_KEY, LLM_MODEL_ID, HUB_QDRANT_URL, MEM0_QDRANT_* |
||||||
|
services: |
||||||
|
gateway: |
||||||
|
build: . |
||||||
|
container_name: {{AGENT_ID}} |
||||||
|
network_mode: "host" |
||||||
|
restart: always |
||||||
|
environment: |
||||||
|
- OPENCLAW_GATEWAY_AUTH_MODE=token |
||||||
|
- OPENCLAW_GATEWAY_AUTH_TOKEN=${CONTROL_UI_TOKEN} |
||||||
|
- NODE_OPTIONS=--max-old-space-size=1536 |
||||||
|
- QDRANT_HOST=${HUB_QDRANT_URL} |
||||||
|
- AGENT_TAG={{AGENT_ID}} |
||||||
|
- LLM_BASE_URL=${LLM_BASE_URL} |
||||||
|
- LLM_API_KEY=${LLM_API_KEY} |
||||||
|
- LLM_MODEL_ID=${LLM_MODEL_ID} |
||||||
|
- MEM0_QDRANT_HOST=${MEM0_QDRANT_HOST} |
||||||
|
- MEM0_QDRANT_PORT=${MEM0_QDRANT_PORT} |
||||||
|
volumes: |
||||||
|
- ./config/openclaw.json:/root/.openclaw/openclaw.json |
||||||
|
- ./skills:/root/.openclaw/workspace/skills |
||||||
|
- ./plugins:/root/.openclaw/workspace/plugins |
||||||
|
- ./archive:/root/.openclaw/workspace/archive |
||||||
|
- ./agents:/root/.openclaw/workspace/agents |
||||||
@ -0,0 +1,226 @@ |
|||||||
|
#!/bin/bash |
||||||
|
############################################################################### |
||||||
|
# Generate a new remote agent instance from the template. |
||||||
|
# - Interactive mode: no flags, prompts for values. |
||||||
|
# - Non-interactive (ChatOps) mode: any flag (-a/-n/-p/-u/-k/-m/-t) enables it; |
||||||
|
# all required params must be provided, otherwise exits with JSON error. |
||||||
|
############################################################################### |
||||||
|
set -e |
||||||
|
|
||||||
|
WORKSPACE="${WORKSPACE:-/root/.openclaw/workspace}" |
||||||
|
TEMPLATE_DIR="$WORKSPACE/remote-blueprints/template" |
||||||
|
|
||||||
|
RED='\033[0;31m' |
||||||
|
GREEN='\033[0;32m' |
||||||
|
YELLOW='\033[1;33m' |
||||||
|
BLUE='\033[0;34m' |
||||||
|
NC='\033[0m' |
||||||
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } |
||||||
|
log_ok() { echo -e "${GREEN}[OK]${NC} $1"; } |
||||||
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } |
||||||
|
log_err() { echo -e "${RED}[ERROR]${NC} $1"; } |
||||||
|
|
||||||
|
# ---------- parse flags (non-interactive mode detection) ---------- |
||||||
|
NONINTERACTIVE=false |
||||||
|
AGENT_ID="" |
||||||
|
AGENT_NAME="" |
||||||
|
PROJECT_ID="" |
||||||
|
LLM_BASE_URL="" |
||||||
|
LLM_API_KEY="" |
||||||
|
LLM_MODEL_ID="" |
||||||
|
CONTROL_UI_TOKEN="" |
||||||
|
|
||||||
|
while getopts "a:n:p:u:k:m:t:" opt; do |
||||||
|
NONINTERACTIVE=true |
||||||
|
case "$opt" in |
||||||
|
a) AGENT_ID="$OPTARG" ;; |
||||||
|
n) AGENT_NAME="$OPTARG" ;; |
||||||
|
p) PROJECT_ID="$OPTARG" ;; |
||||||
|
u) LLM_BASE_URL="$OPTARG" ;; |
||||||
|
k) LLM_API_KEY="$OPTARG" ;; |
||||||
|
m) LLM_MODEL_ID="$OPTARG" ;; |
||||||
|
t) CONTROL_UI_TOKEN="$OPTARG" ;; |
||||||
|
*) ;; |
||||||
|
esac |
||||||
|
done |
||||||
|
shift $((OPTIND-1)) |
||||||
|
|
||||||
|
# ---------- interactive fallback (no flags at all) ---------- |
||||||
|
if [ "$NONINTERACTIVE" = false ]; then |
||||||
|
echo -n "AGENT_ID (required): " |
||||||
|
read -r AGENT_ID |
||||||
|
if [ -z "$AGENT_ID" ]; then |
||||||
|
log_err "AGENT_ID is required." |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
echo -n "AGENT_NAME (optional, default = AGENT_ID): " |
||||||
|
read -r AGENT_NAME |
||||||
|
echo -n "PROJECT_ID (optional, default = default): " |
||||||
|
read -r PROJECT_ID |
||||||
|
|
||||||
|
echo -n "LLM_BASE_URL (required): " |
||||||
|
read -r LLM_BASE_URL |
||||||
|
echo -n "LLM_API_KEY (required): " |
||||||
|
read -r LLM_API_KEY |
||||||
|
echo -n "LLM_MODEL_ID (required, e.g. qwen-max, gpt-4o): " |
||||||
|
read -r LLM_MODEL_ID |
||||||
|
|
||||||
|
echo -n "CONTROL_UI_TOKEN (optional, auto-generate if empty): " |
||||||
|
read -r CONTROL_UI_TOKEN |
||||||
|
else |
||||||
|
# ---------- strict non-interactive mode ---------- |
||||||
|
missing=() |
||||||
|
[ -z "$AGENT_ID" ] && missing+=("AGENT_ID") |
||||||
|
[ -z "$LLM_BASE_URL" ] && missing+=("LLM_BASE_URL") |
||||||
|
[ -z "$LLM_API_KEY" ] && missing+=("LLM_API_KEY") |
||||||
|
[ -z "$LLM_MODEL_ID" ] && missing+=("LLM_MODEL_ID") |
||||||
|
|
||||||
|
if [ ${#missing[@]} -ne 0 ]; then |
||||||
|
# JSON error for ChatOps callers |
||||||
|
printf '{"ok":false,"error":"missing_required_params","missing":[' >&2 |
||||||
|
for i in "${!missing[@]}"; do |
||||||
|
[ "$i" -ne 0 ] && printf ',' >&2 |
||||||
|
printf '"%s"' "${missing[$i]}" >&2 |
||||||
|
done |
||||||
|
printf ']}' >&2 |
||||||
|
echo >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
# Defaults for optional values |
||||||
|
[ -z "$AGENT_NAME" ] && AGENT_NAME="$AGENT_ID" |
||||||
|
[ -z "$PROJECT_ID" ] && PROJECT_ID="default" |
||||||
|
|
||||||
|
# ---------- validate AGENT_ID ---------- |
||||||
|
if ! echo "$AGENT_ID" | grep -qE '^[a-zA-Z0-9_-]+$'; then |
||||||
|
log_err "AGENT_ID must contain only letters, numbers, hyphens, and underscores." |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# ---------- ensure template dir exists ---------- |
||||||
|
if [ ! -d "$TEMPLATE_DIR" ]; then |
||||||
|
log_err "Template not found: $TEMPLATE_DIR" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# ---------- auto-generate CONTROL_UI_TOKEN if empty ---------- |
||||||
|
if [ -z "$CONTROL_UI_TOKEN" ]; then |
||||||
|
if command -v openssl >/dev/null 2>&1; then |
||||||
|
CONTROL_UI_TOKEN=$(openssl rand -hex 24) |
||||||
|
log_info "Generated CONTROL_UI_TOKEN via openssl." |
||||||
|
else |
||||||
|
CONTROL_UI_TOKEN=$(head -c 32 /dev/urandom | base64 | tr -dc 'a-f0-9' | head -c 48) |
||||||
|
log_warn "openssl not found; CONTROL_UI_TOKEN generated via /dev/urandom fallback." |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
INSTANCE_DIR="$WORKSPACE/remote-blueprints/$AGENT_ID" |
||||||
|
if [ -d "$INSTANCE_DIR" ]; then |
||||||
|
if [ "$NONINTERACTIVE" = true ]; then |
||||||
|
log_err "Instance already exists: $INSTANCE_DIR" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
log_warn "Instance already exists: $INSTANCE_DIR" |
||||||
|
echo -n "Overwrite? (y/N): " |
||||||
|
read -r confirm |
||||||
|
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then |
||||||
|
log_info "Aborted." |
||||||
|
exit 0 |
||||||
|
fi |
||||||
|
rm -rf "$INSTANCE_DIR" |
||||||
|
fi |
||||||
|
|
||||||
|
# ---------- copy template ---------- |
||||||
|
log_info "Copying template to $INSTANCE_DIR ..." |
||||||
|
mkdir -p "$INSTANCE_DIR" |
||||||
|
cp -r "$TEMPLATE_DIR"/* "$INSTANCE_DIR/" |
||||||
|
[ -f "$TEMPLATE_DIR/.env.tpl" ] && cp "$TEMPLATE_DIR/.env.tpl" "$INSTANCE_DIR/.env.tpl" |
||||||
|
log_ok "Copy done." |
||||||
|
|
||||||
|
# ---------- render templates (safe sed with # delimiter) ---------- |
||||||
|
escape_sed_val() { |
||||||
|
local v="$1" |
||||||
|
v="${v//\\/\\\\}" |
||||||
|
v="${v//&/\\&}" |
||||||
|
v="${v//\//\\/}" |
||||||
|
printf '%s' "$v" |
||||||
|
} |
||||||
|
|
||||||
|
AGENT_NAME_ESC=$(escape_sed_val "$AGENT_NAME") |
||||||
|
PROJECT_ID_ESC=$(escape_sed_val "$PROJECT_ID") |
||||||
|
LLM_BASE_URL_ESC=$(escape_sed_val "$LLM_BASE_URL") |
||||||
|
LLM_API_KEY_ESC=$(escape_sed_val "$LLM_API_KEY") |
||||||
|
LLM_MODEL_ID_ESC=$(escape_sed_val "$LLM_MODEL_ID") |
||||||
|
CONTROL_UI_TOKEN_ESC=$(escape_sed_val "$CONTROL_UI_TOKEN") |
||||||
|
|
||||||
|
# Render all *.tpl and .env.tpl files |
||||||
|
while IFS= read -r -d '' f; do |
||||||
|
log_info "Rendering $f ..." |
||||||
|
sed -i "s#{{AGENT_ID}}#$AGENT_ID#g" "$f" |
||||||
|
sed -i "s#{{AGENT_NAME}}#$AGENT_NAME_ESC#g" "$f" |
||||||
|
sed -i "s#{{PROJECT_ID}}#$PROJECT_ID_ESC#g" "$f" |
||||||
|
sed -i "s#{{LLM_BASE_URL}}#$LLM_BASE_URL_ESC#g" "$f" |
||||||
|
sed -i "s#{{LLM_API_KEY}}#$LLM_API_KEY_ESC#g" "$f" |
||||||
|
sed -i "s#{{LLM_MODEL_ID}}#$LLM_MODEL_ID_ESC#g" "$f" |
||||||
|
sed -i "s#{{CONTROL_UI_TOKEN}}#$CONTROL_UI_TOKEN_ESC#g" "$f" |
||||||
|
# Backward-compat: clean any legacy BAILIAN placeholders if present |
||||||
|
sed -i "s#{{BAILIAN_API_KEY}}#$LLM_API_KEY_ESC#g" "$f" || true |
||||||
|
|
||||||
|
done < <(find "$INSTANCE_DIR" -type f \( -name '*.tpl' -o -name '.env.tpl' \) -print0) |
||||||
|
|
||||||
|
# ---------- rename agents/{{AGENT_ID}}.json.tpl -> agents/<AGENT_ID>.json.tpl (before generic .tpl removal) ---------- |
||||||
|
if [ -f "$INSTANCE_DIR/agents/{{AGENT_ID}}.json.tpl" ]; then |
||||||
|
mv "$INSTANCE_DIR/agents/{{AGENT_ID}}.json.tpl" "$INSTANCE_DIR/agents/$AGENT_ID.json.tpl" |
||||||
|
fi |
||||||
|
|
||||||
|
# ---------- rename all *.tpl to final filenames ---------- |
||||||
|
while IFS= read -r -d '' f; do |
||||||
|
base="${f%.tpl}" |
||||||
|
mv "$f" "$base" |
||||||
|
log_info "Renamed to $base" |
||||||
|
done < <(find "$INSTANCE_DIR" -type f -name '*.tpl' -print0) |
||||||
|
|
||||||
|
# .env.tpl -> .env |
||||||
|
if [ -f "$INSTANCE_DIR/.env.tpl" ]; then |
||||||
|
mv "$INSTANCE_DIR/.env.tpl" "$INSTANCE_DIR/.env" |
||||||
|
log_info "Renamed .env.tpl to .env" |
||||||
|
fi |
||||||
|
|
||||||
|
# ---------- generate deploy_to_target.sh ---------- |
||||||
|
DEPLOY_SCRIPT="$INSTANCE_DIR/deploy_to_target.sh" |
||||||
|
cat > "$DEPLOY_SCRIPT" << 'DEPLOYEOF' |
||||||
|
#!/bin/bash |
||||||
|
# Deploy this agent directory to a remote host. Usage: ./deploy_to_target.sh <TARGET_IP> [SSH_USER] |
||||||
|
set -e |
||||||
|
|
||||||
|
TARGET_IP="${1:?Usage: $0 <TARGET_IP> [SSH_USER]}" |
||||||
|
SSH_USER="${2:-root}" |
||||||
|
AGENT_ID="__AGENT_ID_PLACEHOLDER__" |
||||||
|
REMOTE_PATH="/opt/openclaw-remote/$AGENT_ID" |
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
||||||
|
|
||||||
|
if [ ! -f "$SCRIPT_DIR/docker-compose.yml" ]; then |
||||||
|
echo "[ERROR] docker-compose.yml not found in $SCRIPT_DIR" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
echo "[INFO] Syncing $SCRIPT_DIR to ${SSH_USER}@${TARGET_IP}:$REMOTE_PATH ..." |
||||||
|
ssh "${SSH_USER}@${TARGET_IP}" "mkdir -p $REMOTE_PATH" |
||||||
|
(cd "$SCRIPT_DIR" && tar cf - .) | ssh "${SSH_USER}@${TARGET_IP}" "cd $REMOTE_PATH && tar xf -" |
||||||
|
|
||||||
|
echo "[INFO] Remote: docker compose down && docker compose up -d --build ..." |
||||||
|
ssh "${SSH_USER}@${TARGET_IP}" "cd $REMOTE_PATH && docker compose down 2>/dev/null || true && docker compose up -d --build" |
||||||
|
|
||||||
|
echo "[OK] Deploy done." |
||||||
|
DEPLOYEOF |
||||||
|
|
||||||
|
# inject actual AGENT_ID into deploy script |
||||||
|
sed -i "s#__AGENT_ID_PLACEHOLDER__#$AGENT_ID#g" "$DEPLOY_SCRIPT" |
||||||
|
chmod +x "$DEPLOY_SCRIPT" |
||||||
|
log_ok "Generated $DEPLOY_SCRIPT" |
||||||
|
|
||||||
|
log_ok "Instance ready: $INSTANCE_DIR" |
||||||
|
echo "[OK] CONTROL_UI_TOKEN: $CONTROL_UI_TOKEN" |
||||||
|
echo "Next: cd $INSTANCE_DIR && ./deploy_to_target.sh <TARGET_IP> [SSH_USER]" |
||||||
@ -0,0 +1,60 @@ |
|||||||
|
#!/bin/bash |
||||||
|
############################################################################### |
||||||
|
# Sync a skill (or plugin) directory to a remote agent and restart the container. |
||||||
|
# Usage: ./sync_skill.sh <TARGET_IP> <AGENT_ID> <MODULE_DIR_NAME> |
||||||
|
# MODULE_DIR_NAME = directory under workspace/skills/ (e.g. tavily, mem0-integration) |
||||||
|
# Prefer rsync (exclude node_modules); fallback to scp if rsync not available. |
||||||
|
############################################################################### |
||||||
|
set -e |
||||||
|
|
||||||
|
WORKSPACE="${WORKSPACE:-/root/.openclaw/workspace}" |
||||||
|
SKILLS_SRC="$WORKSPACE/skills" |
||||||
|
REMOTE_BASE="/opt/openclaw-remote" |
||||||
|
|
||||||
|
RED='\033[0;31m' |
||||||
|
GREEN='\033[0;32m' |
||||||
|
YELLOW='\033[1;33m' |
||||||
|
BLUE='\033[0;34m' |
||||||
|
NC='\033[0m' |
||||||
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } |
||||||
|
log_ok() { echo -e "${GREEN}[OK]${NC} $1"; } |
||||||
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } |
||||||
|
log_err() { echo -e "${RED}[ERROR]${NC} $1"; } |
||||||
|
|
||||||
|
# --- 1. Parameter check --- |
||||||
|
TARGET_IP="${1:?Usage: $0 <TARGET_IP> <AGENT_ID> <MODULE_DIR_NAME>}" |
||||||
|
AGENT_ID="${2:?Usage: $0 <TARGET_IP> <AGENT_ID> <MODULE_DIR_NAME>}" |
||||||
|
MODULE_NAME="${3:?Usage: $0 <TARGET_IP> <AGENT_ID> <MODULE_DIR_NAME>}" |
||||||
|
|
||||||
|
LOCAL_PATH="$SKILLS_SRC/$MODULE_NAME" |
||||||
|
REMOTE_PATH="$REMOTE_BASE/$AGENT_ID/skills" |
||||||
|
|
||||||
|
# --- 2. Local path exists --- |
||||||
|
if [ ! -d "$LOCAL_PATH" ]; then |
||||||
|
log_err "Local path not found: $LOCAL_PATH" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# --- 3. Optional: quick SSH connectivity check --- |
||||||
|
if ! ssh -o ConnectTimeout=5 -o BatchMode=yes "root@$TARGET_IP" "exit" 2>/dev/null; then |
||||||
|
log_warn "SSH to root@$TARGET_IP may require password or key. Continuing anyway." |
||||||
|
fi |
||||||
|
|
||||||
|
# --- 4. Sync: prefer rsync, fallback scp --- |
||||||
|
if command -v rsync >/dev/null 2>&1; then |
||||||
|
log_info "Syncing with rsync (excluding node_modules): $LOCAL_PATH -> root@$TARGET_IP:$REMOTE_PATH/" |
||||||
|
rsync -avz --exclude 'node_modules' "$LOCAL_PATH/" "root@${TARGET_IP}:${REMOTE_PATH}/${MODULE_NAME}/" |
||||||
|
log_ok "Rsync done." |
||||||
|
else |
||||||
|
log_warn "rsync not found; using scp (slower, includes node_modules)." |
||||||
|
log_info "Syncing: $LOCAL_PATH -> root@$TARGET_IP:$REMOTE_PATH/" |
||||||
|
ssh "root@$TARGET_IP" "mkdir -p $REMOTE_PATH" |
||||||
|
scp -r "$LOCAL_PATH" "root@${TARGET_IP}:${REMOTE_PATH}/" |
||||||
|
log_ok "Scp done." |
||||||
|
fi |
||||||
|
|
||||||
|
# --- 5. Restart remote container --- |
||||||
|
log_info "Restarting container: ssh root@$TARGET_IP 'cd $REMOTE_BASE/$AGENT_ID && docker compose restart'" |
||||||
|
ssh "root@$TARGET_IP" "cd $REMOTE_BASE/$AGENT_ID && docker compose restart" |
||||||
|
|
||||||
|
log_ok "Sync and restart completed." |
||||||
@ -1,36 +1,27 @@ |
|||||||
{ |
{ |
||||||
"name": "daily-horoscope", |
"id": "daily-horoscope", |
||||||
|
"name": "Daily Horoscope", |
||||||
"version": "1.0.0", |
"version": "1.0.0", |
||||||
"description": "Daily horoscope and fortune analysis with Chinese almanac integration", |
"description": "Daily horoscope and fortune analysis with Chinese almanac integration", |
||||||
"main": "index.js", |
"main": "index.js", |
||||||
"type": "skill", |
"type": "plugin", |
||||||
|
"configSchema": { |
||||||
|
"type": "object", |
||||||
|
"properties": { |
||||||
|
"enabled": { "type": "boolean", "default": true } |
||||||
|
} |
||||||
|
}, |
||||||
"tools": [ |
"tools": [ |
||||||
{ |
{ |
||||||
"name": "getDailyHoroscope", |
"name": "getDailyHoroscope", |
||||||
"description": "Get daily horoscope for all 12 zodiac signs and analyze with user's birth chart", |
"description": "Get daily horoscope and fortune analysis", |
||||||
"inputSchema": { |
"inputSchema": { |
||||||
"type": "object", |
"type": "object", |
||||||
"properties": { |
"properties": { |
||||||
"date": { |
"date": { "type": "string", "description": "Target date YYYY-MM-DD" } |
||||||
"type": "string", |
}, |
||||||
"description": "Target date in YYYY-MM-DD format" |
"required": ["date"] |
||||||
}, |
|
||||||
"userBirthInfo": { |
|
||||||
"type": "object", |
|
||||||
"properties": { |
|
||||||
"birthday": { "type": "string" }, |
|
||||||
"birthTime": { "type": "string" }, |
|
||||||
"zodiacSign": { "type": "string" } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
} |
||||||
} |
} |
||||||
], |
] |
||||||
"skills": { |
|
||||||
"entries": { |
|
||||||
"chinese-almanac": { "enabled": true }, |
|
||||||
"tavily": { "enabled": true } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,13 @@ |
|||||||
|
# Skills 共享模块 |
||||||
|
|
||||||
|
供各 Skill 复用的公共代码。 |
||||||
|
|
||||||
|
## llm_client.js |
||||||
|
|
||||||
|
OpenClaw 与 OneAPI 网关对接的共享 LLM 客户端:按模型名调用 OpenAI 兼容的 Chat Completions API。 |
||||||
|
|
||||||
|
- **环境变量**:`LLM_BASE_URL`、`LLM_API_KEY` |
||||||
|
- **导出**:`callSpecificModel(modelName, messages, options)`(不支持 stream,支持 `timeoutMs`) |
||||||
|
- **错误与日志**:非 200 与超时时会打印 `[LLM_Client] Error calling <model>:` 并抛出带详情的 Error |
||||||
|
|
||||||
|
完整架构与使用说明见:[workspace/docs/LLM_GATEWAY_AND_SKILL_CLIENT.md](../../docs/LLM_GATEWAY_AND_SKILL_CLIENT.md) |
||||||
@ -0,0 +1,130 @@ |
|||||||
|
/** |
||||||
|
* Shared LLM client for OpenClaw Skills. |
||||||
|
* Calls OneAPI (or any OpenAI-compatible) gateway with a specific model. |
||||||
|
* Requires: LLM_BASE_URL, LLM_API_KEY in environment. |
||||||
|
*/ |
||||||
|
|
||||||
|
const LOG_PREFIX = '[LLM_Client]'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Build chat completions URL from base. Avoids double /v1 when user sets |
||||||
|
* LLM_BASE_URL to e.g. http://100.x:3000/v1.
|
||||||
|
* @param {string} baseUrl - LLM_BASE_URL (may end with / or /v1) |
||||||
|
* @returns {string} full URL for POST |
||||||
|
*/ |
||||||
|
function buildChatCompletionsUrl(baseUrl) { |
||||||
|
const base = (baseUrl || '').replace(/\/+$/, ''); |
||||||
|
if (!base) return ''; |
||||||
|
if (base.endsWith('/v1')) { |
||||||
|
return `${base}/chat/completions`; |
||||||
|
} |
||||||
|
return `${base}/v1/chat/completions`; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Parse OneAPI/OpenAI error body for message. |
||||||
|
* @param {string} text - response text |
||||||
|
* @returns {string} error message for display |
||||||
|
*/ |
||||||
|
function parseErrorBody(text) { |
||||||
|
if (!text || typeof text !== 'string') return String(text || 'Unknown error'); |
||||||
|
try { |
||||||
|
const obj = JSON.parse(text); |
||||||
|
if (obj.error && typeof obj.error === 'object' && typeof obj.error.message === 'string') return obj.error.message; |
||||||
|
if (obj.error && typeof obj.error === 'string') return obj.error; |
||||||
|
if (typeof obj.message === 'string') return obj.message; |
||||||
|
return text; |
||||||
|
} catch { |
||||||
|
return text; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Call a specific model via the configured LLM gateway (OpenAI Chat Completions). |
||||||
|
* @param {string} modelName - Model id (e.g. "qwen3.5-plus", "claude-3-sonnet") |
||||||
|
* @param {Array<{role: string, content: string}>} messages - Chat messages |
||||||
|
* @param {object} options - Optional: temperature, max_tokens, stream, timeoutMs (client-only, default 60000) |
||||||
|
* @returns {Promise<object>} Parsed JSON response (e.g. choices, usage) |
||||||
|
* @throws {Error} On HTTP error or timeout; message/cause include OneAPI error details |
||||||
|
*/ |
||||||
|
async function callSpecificModel(modelName, messages, options = {}) { |
||||||
|
if (!Array.isArray(messages)) { |
||||||
|
const err = new Error('messages must be an array'); |
||||||
|
err.code = 'LLM_CLIENT_CONFIG'; |
||||||
|
throw err; |
||||||
|
} |
||||||
|
if (options.stream === true) { |
||||||
|
const err = new Error('Stream mode is not supported by this client; use stream: false or omit'); |
||||||
|
err.code = 'LLM_CLIENT_CONFIG'; |
||||||
|
throw err; |
||||||
|
} |
||||||
|
|
||||||
|
const baseUrl = (process.env.LLM_BASE_URL || '').trim(); |
||||||
|
const apiKey = (process.env.LLM_API_KEY || '').trim(); |
||||||
|
|
||||||
|
if (!baseUrl || !apiKey) { |
||||||
|
const err = new Error('LLM_BASE_URL and LLM_API_KEY must be set in environment'); |
||||||
|
err.code = 'LLM_CLIENT_CONFIG'; |
||||||
|
throw err; |
||||||
|
} |
||||||
|
|
||||||
|
const url = buildChatCompletionsUrl(baseUrl); |
||||||
|
if (!url) { |
||||||
|
const err = new Error('Invalid LLM_BASE_URL'); |
||||||
|
err.code = 'LLM_CLIENT_CONFIG'; |
||||||
|
throw err; |
||||||
|
} |
||||||
|
|
||||||
|
const timeoutMs = options.timeoutMs != null ? Number(options.timeoutMs) : 60000; |
||||||
|
const { timeoutMs: _drop, ...bodyOptions } = options; |
||||||
|
const body = { |
||||||
|
model: modelName, |
||||||
|
messages, |
||||||
|
...bodyOptions, |
||||||
|
}; |
||||||
|
|
||||||
|
const controller = new AbortController(); |
||||||
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs); |
||||||
|
|
||||||
|
try { |
||||||
|
const response = await fetch(url, { |
||||||
|
method: 'POST', |
||||||
|
headers: { |
||||||
|
'Content-Type': 'application/json', |
||||||
|
Authorization: `Bearer ${apiKey}`, |
||||||
|
}, |
||||||
|
body: JSON.stringify(body), |
||||||
|
signal: controller.signal, |
||||||
|
}); |
||||||
|
|
||||||
|
clearTimeout(timeoutId); |
||||||
|
|
||||||
|
if (!response.ok) { |
||||||
|
const rawText = await response.text(); |
||||||
|
const errorSummary = parseErrorBody(rawText); |
||||||
|
const err = new Error(`LLM gateway error (${response.status}): ${errorSummary}`); |
||||||
|
err.status = response.status; |
||||||
|
err.body = rawText; |
||||||
|
err.cause = { message: errorSummary, status: response.status }; |
||||||
|
console.error(`${LOG_PREFIX} Error calling ${modelName}: ${errorSummary}`); |
||||||
|
throw err; |
||||||
|
} |
||||||
|
|
||||||
|
return await response.json(); |
||||||
|
} catch (err) { |
||||||
|
clearTimeout(timeoutId); |
||||||
|
if (err.name === 'AbortError') { |
||||||
|
const timeoutErr = new Error(`LLM request timed out after ${timeoutMs}ms`); |
||||||
|
timeoutErr.code = 'ETIMEDOUT'; |
||||||
|
timeoutErr.cause = err; |
||||||
|
console.error(`${LOG_PREFIX} Error calling ${modelName}: timeout (${timeoutMs}ms)`); |
||||||
|
throw timeoutErr; |
||||||
|
} |
||||||
|
throw err; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
callSpecificModel, |
||||||
|
buildChatCompletionsUrl, |
||||||
|
}; |
||||||
Loading…
Reference in new issue