他淡然一笑,很简单,我当前端不就是了。... 一瞬间,写字楼再次一寂。我乃大专巅峰,何人敢叼我?何人能叼我?他口中低吟道:写字楼中寒风吹,前端切图仔回归。一号工位黑奴泪,褪去校服人向北。无休改稿万人退,三千工资空落泪。宿命天成当前端,前端悔而我不悔!

2025 年 12 月 13 日,VeloxCon China 2025 在北京成功举办。作为 Velox 项目首次在中国举办的线下技术大会,汇聚了来自Meta、IBM、蚂蚁集团、阿里云、腾讯、小米、小红书等企业的数十位核心贡献者与一线工程师。

大会通过 18 场演讲将 Velox 置于真实业务场景之中,系统展示了其在架构演进、AI 数据处理、湖仓加速、流批融合等方向的最新实践。这些分享不仅直面性能、稳定性与兼容性等落地挑战,也反应了开发者社区对构建可靠、可扩展、可协同的数据基础设施的共同探索,彰显了中国开发者在全球高性能分析生态中的工程深度与协作广度。

夯实底座,突破能力边界
会议伊始,Velox 项目联合发起人 Pedro 发表开幕致辞。他回顾了 Velox 开源项目的发展历程,从项目启动、开源发布到建立技术治理结构,展示了 Axiom 架构、GPU 支持、PyVelox 等关键进展,强调了社区协作与工程严谨性是项目持续演进的核心动力。他特别提到,Velox 已建立了正式的技术治理机制,并迎来来自 IBM、Intel、NVIDIA、Microsoft 等多家企业的新增维护者,标志着项目正迈向更加开放和可持续的阶段。

在明确了社区与架构演进的总体方向后,大会议题迅速深入到如何利用 Velox 构建高性能计算引擎的具体实践中。阿里云 EMR Serverless Spark 技术负责人周克勇系统阐述了“可组合性”在数据计算领域的实践。他详细解析了阿里云如何深度集成并贡献于 Apache Celeborn、Paimon、Velox 及 Gluten 等开源组件,通过模块化组装构建出高性能湖仓一体引擎。他指出,基于该架构,阿里云 EMR Serverless Spark 成功创造了 TPC-DS 100TB 规模性能测试的世界新纪录,实现性能翻倍与性价比大幅提升。

接着,Meta 软件工程师 Masha Basmanova 阐述了现有查询引擎在跨语言通信、优化器能力与开发体验上面临的挑战,并介绍了基于 C++ 的统一前端框架 Axiom。该框架将 SQL 解析、逻辑优化与物理执行融为一体,通过内置的强大优化器与 Velox 运行时无缝对接,能够实现更高效、可扩展的查询处理。演讲最后,她积极展示了 Axiom 的开源路线图,并欢迎全球开发者加入,共同推动该项目的演进。

强大的执行框架,最终需要服务于极具挑战性的数据场景,特别是爆发式增长的 AI 数据。Meta 软件工程师孟晓烜则在之后的演讲中,深入阐述了应对AI训练数据规模激增与成本挑战的解决方案。他重点介绍了 Meta 如何通过数据归一化技术剥离重复特征,并构建可索引的序列存储系统。依托 Velox 技术栈,团队在训练数据的加载、生成与探索三大环节实现了端到端优化,显著提升了处理效率与资源利用率。

在 Meta 多位工程师从框架演进、可组合架构、数据标准化等角度深入分享后,蚂蚁集团高级技术专家黄叶伟也从企业落地实践层面分享了基于 Velox 的 Spark 加速实践。他重点介绍了基于 Gluten 与 Velox 构建的向量化引擎如何通过任务级 Fallback、Spill 优化、Shuffle 优化等关键技术,在混合部署场景下显著提升 Spark 性能与稳定性。他表示,该方案目前已实现日均数十万任务覆盖,平均节省资源超30%,并将在算子优化与架构扩展方面持续演进。

作为连接 Spark 生态与原生加速的关键中间层,Apache Gluten 的进展同样备受关注。来自 IBM 的莫芮与周渊聚焦 Apache Gluten与 Velox 的深度集成,阐述了其如何在大数据分析中驱动创新。他们介绍,Gluten 在保持对 Spark/Flink 作业透明加速能力的同时,正逐步增强对多后端引擎和复杂业务场景的适配能力。目前,该方案已在 Pinterest、顺丰科技及多个内部集群完成规模化验证,有效支撑了从日志分析到物流调度等多样化负载的性能提升与成本优化。

随着向量化加速在通用场景日趋成熟,针对特定存储格式的深度优化成为新的效能突破口。腾讯大数据开发工程师陈锦海分享了微信基于 Velox 加速 lceberg 湖仓分析的优化与实践,重点介绍了原生分桶方案。据他介绍,该方案通过动态识别表元信息自动设置分区数,能有效缓解 AQE 引发的写入倾斜,结合空闲资源灰度发布策略,可保障大规模作业的稳定上线。

扎根场景,释放协同效能
午餐后的议程更加聚焦 Velox 在真实业务中的集成深度与生产韧性,回应了开发者们对兼容性、稳定性与端到端效能等规模化落地的核心关切。
小米计算平台计算引擎负责人王胜杰分享了公司在 Spark 向量化升级中的规模化落地经验。面对业务迁移中的兼容性与稳定性挑战,他表示,小米通过自动兼容校验、双跑结果比对及内存异常感知的三级资源升级机制,已成功推动向量化改造在数十万作业中平稳落地。

面对海量数据挑战,全球科技公司也在探索相似的演进路径。Meta 软件工程经理 Stanley Yao 在演讲中分享了公司基于 Velox 推进 Spark 向量化改造的整体策略。他表示,团队通过从定制化方案到开源架构的持续演进,已实现关键业务管线向 Gluten(Flare)的平稳迁移,并获得显著的效率提升。未来,Meta 计划进一步扩大该架构的应用规模。

在 CPU 向量化趋于普及的同时,利用异构硬件挖掘更高性能成为新的前沿。IBM 研究院资深软件工程师 Zoltán Arnold Nagy 展示了基于 Velox 与 Presto 的 GPU 加速数据处理方案。他介绍道,Velox 通过与 cuDF 集成,可在 GPU 上高效执行算⼦,并针对多 GPU 分布式场景优化通信与数据交换。此外,为突破 I/O 瓶颈,团队正在探索结合 GPUDirect 存储与缓存层的加速策略。

对性能与稳定性的追求,也驱动着查询引擎架构本身的融合与创新。Meta 软件工程师谭家梁与大家分享了 Native Presto-on-Spark 的规模化应用。该架构以 Presto 查询优化、Spark 资源调度与容错机制以及 Velox 原生向量化执行为核心,实现了性能与可靠性的显著提升。他表示,目前该方案已在生产环境中取得成效,并将在未来持续推进全栈原生化演进。

对于国内庞大的云上业务,Velox 同样在支撑着关键数据服务平台。 阿里云高级工程师王彬与范阿冬系统介绍了Velox在阿里云日志服务中的深度集成与应用。他们指出,基于 Velox 构建的高性能查询引擎,通过混合执行、表达式下推、自动增量物化视图及免 Schema 分析等核心技术,可显著提升平台在处理海量实时数据时的查询效率与资源利用率。他们还强调,该架构不仅为日志分析、智能运维等场景提供了稳定支撑,也为面向 AI 的云原生数据平台演进奠定了坚实基础。

除了通用的日志与湖仓分析,Velox 也在向更垂直的时序数据场景渗透。腾讯高级工程师李兆龙分享了基于 Velox 构建云原生时序数据库的落地经验。他表示,通过在 Velox 中实现时序数据去重优化与存储写入增强,系统在应对高频写入与实时查询场景时,可显著提升吞吐效率与响应性能。目前该方案已有效支持物联网、实时监控等业务场景,未来还将进一步完善缓存与压缩机制,持续优化时序数据处理的整体效能。

IBM 软件工程师刘平接着分享了 Velox 在 Iceberg 数据写入能力上的突破性进展。他表示,目前 Velox 对 Iceberg 的支持以读取为主,其写入功能的完善将填补该方向的关键能力空白,为基于 Presto 与 Spark 的数据湖架构提供更统一、高效的数据摄入层。这一进展也标志着 Velox 正从查询加速向数据全链路处理拓展。

接着,来自阿里云的毕岩与周滔分享了 Velox 与 Apache Paimon 深度集成的解决方案,为提升引擎与存储的协同效率提供了另一种集成思路。在他们看来,现有方案存在表类型支持受限、缺乏可移植性等瓶颈, 但可以建立 C++ 原生 Paimon 库,通过其统一的数据协议与插件化设计,使 Paimon 能够被 Velox、StarRocks 等多种计算引擎直接高效调用,从而提升数据读写性能,并为湖仓格式的跨引擎协同提供新的基础支撑。

在批处理场景之外,流计算框架的向量化也正成为新的热点。蚂蚁集团技术专家刘勇介绍了基于 Velox 为 Flink 构建的统一向量化执行引擎 Flex。他表示,Flink 作为流批一体架构的核心,其原生向量化能力的补足至关重要。Flex 通过将 Velox 的高性能算子能力引入 Flink,同时结合自动化验证、可视化计划与精细化回退机制,现已实现了作业性能的显著提升,并支撑多条核心业务链路平稳运行。

随着 Velox 赋能的应用场景日益广泛和复杂,确保其在不同引擎和版本间的整体质量与可靠性变得至关重要。Meta 软件工程师 Eric Liu 阐述了在 AI 数据基础架构下,保障 Velox 多引擎版本可靠性的系统化方法。他指出,面对不同引擎与存储格式交织带来的复杂性,关键在于建立跨引擎测试框架与合成数据工厂。这一实践能有效提前发现全栈潜在问题,从而确保底层变更在大规模生产环境中的稳定与高效。

针对向量化引擎中窗口运算符内存溢出的典型难题,来自英特尔的贾柯分享了她的见解。她认为,通过为 Velox 引入流式窗口处理机制,可使计算随数据到达逐步执行并即时释放内存,从而从架构层面化解多数场景下的内存风险,显著提升复杂查询的稳定性。

最后,小红书 Native Engine 团队技术负责人魏秀利也分享了向量化引擎在公司业务中规模化落地的经验。据他介绍,通过将写入异步化并构建原生 Avro 读取能力,小红书在不增加业务复杂度的前提下,成功缓解了端到端延迟,印证了“执行与存储协同优化”在湖仓场景中的关键价值。

从底层执行引擎的持续创新,到日志分析、湖仓写入、流批融合等复杂场景的稳定运行,在本届 VeloxCon China 上,我们看到 Velox 的技术价值已在真实业务中不断被验证和拓展。同时我们也很高兴看到中国开发者成为这一进程的重要推动者。期待未来有更多志同道合者加入 Velox 开源社区,共建高性能分析基础设施。weibo.com/ttarticle/p/show?id=2309405289958885163025 weibo.com/ttarticle/p/show?id=2309405289959241416746 weibo.com/ttarticle/p/show?id=2309405290066267471927 weibo.com/ttarticle/p/show?id=2309405290066615861284 weibo.com/ttarticle/p/show?id=2309405290067014058071 weibo.com/ttarticle/p/show?id=2309405290067357991296 weibo.com/ttarticle/p/show?id=2309405290067702186269 weibo.com/ttarticle/p/show?id=2309405290068222279690 weibo.com/ttarticle/p/show?id=2309405290068561756401

在进行网络请求时,有时需要通过不同的IP地址来发起请求。本文将从技术实现角度,介绍在 Python 程序中切换出口 IP 的几种常见方法,包括代理IP轮换、多网卡绑定等方案,并提供完整的可运行代码。

运行环境

项目版本
操作系统Ubuntu 22.04 / macOS Ventura
Python3.8+
依赖库requests, aiohttp, itertools

方法一:代理IP轮换

这是最常见的方式,通过维护一个代理IP列表,在每次请求时轮换使用。
基础实现

import requests
from itertools import cycle

# 代理IP列表(示例格式)
PROXY_LIST = [
    'http://user:pass@proxy1.example.com:8080',
    'http://user:pass@proxy2.example.com:8080',
    'http://user:pass@proxy3.example.com:8080',
]

def fetch_with_rotation(url: str, max_attempts: int = 3):
    """
    轮换代理IP发送请求
    """
    proxy_cycle = cycle(PROXY_LIST)
    
    for attempt in range(max_attempts):
        proxy = next(proxy_cycle)
        proxies = {'http': proxy, 'https': proxy}
        
        try:
            response = requests.get(url, proxies=proxies, timeout=10)
            response.raise_for_status()
            print(f"使用代理: {proxy} - 状态码: {response.status_code}")
            return response.text
        except requests.exceptions.RequestException as e:
            print(f"代理 {proxy} 失败: {e}")
            continue
    
    raise Exception(f"所有代理尝试失败,共 {max_attempts} 次")

if __name__ == '__main__':
    result = fetch_with_rotation('https://httpbin.org/ip')
    print(f"响应: {result}")

预期输出

使用代理: http://user:pass@proxy1.example.com:8080 - 状态码: 200
响应: {"origin": "203.0.113.45"}

方法二:随机代理选择

从代理池中随机选取一个IP,适用于不需要严格按顺序轮换的场景。

import random
import requests

def fetch_with_random_proxy(url: str):
    """随机选择代理IP"""
    proxy = random.choice(PROXY_LIST)
    proxies = {'http': proxy, 'https': proxy}
    
    response = requests.get(url, proxies=proxies, timeout=10)
    return response.text

# 使用示例
for i in range(5):
    result = fetch_with_random_proxy('https://httpbin.org/ip')
    print(f"第{i+1}次请求: {result}")

方法三:基于失败率的动态切换

在实际应用中,某些代理可能失效。以下代码实现了失败自动切换机制:

import requests
from queue import Queue
from threading import Lock

class ProxyManager:
    """代理管理器,支持失败自动切换"""
    
    def __init__(self, proxy_list: list):
        self.proxy_list = proxy_list.copy()
        self.current_index = 0
        self.lock = Lock()
        self.failure_count = {p: 0 for p in proxy_list}
        self.max_failures = 3
    
    def get_current_proxy(self):
        with self.lock:
            proxy = self.proxy_list[self.current_index]
            return proxy
    
    def switch_to_next(self):
        with self.lock:
            self.current_index = (self.current_index + 1) % len(self.proxy_list)
            return self.proxy_list[self.current_index]
    
    def report_failure(self, proxy: str):
        """报告代理失败,累计失败次数"""
        self.failure_count[proxy] += 1
        if self.failure_count[proxy] >= self.max_failures:
            print(f"代理 {proxy} 失败次数达上限,将被移除")
            if proxy in self.proxy_list:
                self.proxy_list.remove(proxy)
        self.switch_to_next()
    
    def fetch(self, url: str, max_switches: int = 5):
        """使用管理器发送请求"""
        for _ in range(max_switches):
            proxy = self.get_current_proxy()
            proxies = {'http': proxy, 'https': proxy}
            
            try:
                response = requests.get(url, proxies=proxies, timeout=10)
                response.raise_for_status()
                return response.text
            except requests.exceptions.RequestException as e:
                print(f"代理 {proxy} 请求失败: {e}")
                self.report_failure(proxy)
        
        raise Exception("所有代理均失效")

# 使用示例
manager = ProxyManager(PROXY_LIST)
result = manager.fetch('https://httpbin.org/ip')
print(f"最终结果: {result}")

方法四:异步环境下的代理轮换

对于高并发场景,使用 aiohttp 配合异步轮换:

import asyncio
import aiohttp
from itertools import cycle

async def fetch_async(session: aiohttp.ClientSession, url: str, proxy: str):
    """异步请求函数"""
    try:
        async with session.get(url, proxy=proxy, timeout=10) as resp:
            return await resp.text()
    except Exception as e:
        return f"错误: {e}"

async def batch_fetch_with_proxy_rotation(urls: list, proxy_list: list):
    """批量异步请求,自动轮换代理"""
    proxy_cycle = cycle(proxy_list)
    connector = aiohttp.TCPConnector(limit=10)
    
    async with aiohttp.ClientSession(connector=connector) as session:
        tasks = []
        for url in urls:
            proxy = next(proxy_cycle)
            tasks.append(fetch_async(session, url, proxy))
        
        results = await asyncio.gather(*tasks)
        return results

# 使用示例
async def main():
    urls = ['https://httpbin.org/ip'] * 10
    results = await batch_fetch_with_proxy_rotation(urls, PROXY_LIST)
    for i, res in enumerate(results):
        print(f"请求{i+1}: {res[:100]}")

if __name__ == '__main__':
    asyncio.run(main())

方法五:多网卡环境下的源IP绑定

在服务器配置了多个物理网卡或多个IP地址的情况下,可以通过绑定源IP来实现IP切换:

import socket
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.connection import create_connection

class SourceIPAdapter(HTTPAdapter):
    """自定义适配器,绑定源IP地址"""
    
    def __init__(self, source_ip: str, **kwargs):
        self.source_ip = source_ip
        super().__init__(**kwargs)
    
    def init_poolmanager(self, *args, **kwargs):
        kwargs['source_address'] = (self.source_ip, 0)
        super().init_poolmanager(*args, **kwargs)

def fetch_with_source_ip(url: str, source_ip: str):
    """使用指定源IP发送请求"""
    session = requests.Session()
    adapter = SourceIPAdapter(source_ip)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    
    response = session.get(url, timeout=10)
    return response.text

# 使用示例(假设服务器绑定了多个IP)
# result = fetch_with_source_ip('https://httpbin.org/ip', '192.168.1.100')
# print(result)

方法对比总结

注意事项

  1. 代理IP来源:本文示例中的代理地址为占位符,实际使用时需替换为有效的代理服务地址。
  2. 请求频率:合理控制请求频率,避免对目标服务器造成过大压力。
  3. 异常处理:生产环境建议增加更完善的异常处理和日志记录。
  4. 合规使用:请确保使用代理IP的行为符合目标网站的条款以及相关法律法规。

▍阅读指南

  • 如果你只想要代码:直接跳转第四章,核心实现可复制运行。
  • 如果你想理解设计思路:从第二章开始,拆解 Redis 作为共享总线的工程考量。
  • 如果你关心生产级细节:第五章有踩坑记录与调优参数速查。

一、多策略共享行情的工程难题

1.1 各自订阅的三重代价

当一个量化系统运行多个策略时,最常见的做法是每个策略独立订阅 WebSocket:

# 策略 A
ws_a = await connect("wss://api.example.com/realtime")
await ws_a.send(subscribe(["AAPL.US", "TSLA.US"]))

# 策略 B
ws_b = await connect("wss://api.example.com/realtime")
await ws_b.send(subscribe(["AAPL.US", "700.HK"]))

这种写法在策略数量增加时会暴露三个问题:

问题具体表现量化后果
连接数膨胀10 个策略 × 20 标的 = 10 个 WebSocket 连接服务端订阅上限通常为单连接 50-100 个标的,多连接增加限频风险
断线恢复各自为战网络抖动时,10 个连接各自重连,重试策略不协调部分连接因限频被拒绝,策略数据不同步
跨进程无法共享策略部署在不同进程/容器时,每个进程都需要自己的连接资源浪费,且无法保证数据一致性

数据实测:3 个策略各自订阅 30 个美股标的,网络闪断一次后,平均恢复时间 23 秒,期间三个策略收到的数据最大时间差达到 8 秒。

1.2 三种方案的工程账

方案架构优点致命缺陷
各自订阅每个策略独立连接简单,无耦合连接数爆炸,断线后各自为战
单连接+内部队列一个连接收数据,通过 asyncio.Queue 分发节省连接数单点故障,跨进程无法共享
连接池+Redis连接池写入 Redis,策略独立读取解耦、高可用、跨进程引入 Redis 依赖,需处理数据一致性

▍本章核心结论

  • 多策略共享行情的本质是将“推送”转为“拉取+缓存”——策略不直接依赖连接的稳定性。
  • Redis 作为共享总线的代价是 5-10ms 的写入延迟,换来的是跨进程共享和故障隔离

二、架构总览:从单连接到 Redis 共享总线

2.1 为什么选 Redis

当决定引入中间层时,候选方案对比:

候选方案优势为什么不适用
内存队列(asyncio.Queue)零延迟,无外部依赖无法跨进程,策略必须和连接池在同一进程
Kafka/RabbitMQ持久化,高吞吐运维重,量化策略通常不需要消息回溯到三天前
Redis轻量、支持多种数据结构、量化团队已有Hash 存快照,Pub/Sub 做通知,Streams 存历史——三种模式覆盖全场景

技术类比:Redis 之于行情系统,如同交易所的行情网关之于券商——网关不关心数据被用于何种策略,只负责将数据“放在那里”,策略自行决定何时读取。

2.2 整体架构图

┌─────────────────────────────────────────────────────────────────────┐
│                         行情数据源                                   │
│         单一 WebSocket 连接,跨美股/港股/A股/加密                     │
└──────────────────────────────┬──────────────────────────────────────┘
                               │ 毫秒级推送
                               ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      WebSocket 连接池(Python asyncio)               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐            │
│  │ 连接 #1  │  │ 连接 #2  │  │ 连接 #3  │  │ 热备连接 │            │
│  │ 20个标的 │  │ 20个标的 │  │ 20个标的 │  │  空闲    │            │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘            │
│       │             │             │             │                    │
│       └─────────────┴─────────────┴─────────────┘                    │
│                               │                                      │
│                    ┌──────────┴──────────┐                           │
│                    │   订阅状态持久化     │                           │
│                    │ (Redis Set 存储)    │                           │
│                    └─────────────────────┘                           │
└──────────────────────────────┬──────────────────────────────────────┘
                               │ 写入
                               ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         Redis Server(共享总线)                      │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────┐  │
│  │ Hash: ticker:*  │  │ Pub/Sub 通知    │  │ Streams: tick:*     │  │
│  │ 最新行情快照     │  │ 数据更新广播     │  │ 历史 tick(可选)   │  │
│  └────────┬────────┘  └────────┬────────┘  └──────────┬──────────┘  │
└───────────┼────────────────────┼──────────────────────┼──────────────┘
            │ 读取                │ 订阅                  │ 回放
            ▼                     ▼                       ▼
   ┌─────────────┐        ┌─────────────┐        ┌─────────────┐
   │  策略 A     │        │  策略 B     │        │  策略 C     │
   │ (趋势跟踪)  │        │  (套利)     │        │  (风控)     │
   │ GET ticker:*│        │ SUBSCRIBE   │        │ XREAD stream│
   └─────────────┘        └─────────────┘        └─────────────┘

2.3 组件职责速查

组件职责关键设计
连接池管理器维护多个 WebSocket 连接,负载均衡,故障恢复最少订阅数分配,热备连接,指数退避重连
订阅状态存储将当前订阅列表持久化到 Redis Set重连时从 Redis 读取,自动恢复订阅
Redis 写入器将行情数据写入 Redis Hash/Pub/Sub异步写入,写入失败时本地缓冲
策略消费者按需从 Redis 读取或订阅更新与连接池完全解耦,独立部署

三、核心实现:WebSocket 到 Redis 的数据管道

3.1 连接池与心跳管理

连接池的核心代码已在《WebSocket 连接池生产级实现》中详述。本节聚焦于将消息写入 Redis 的部分。

心跳管理的关键参数:

  • 每 1 秒发送 {"cmd":"ping"}(与服务端协议对齐)
  • 5 秒未收到 pong 判定连接僵死
  • 重连使用指数退避 + 10% 随机抖动,最大延迟 60 秒

3.2 订阅状态的持久化

这是断线恢复的关键。如果没有持久化,重连后连接池不知道之前订阅了哪些标的。

实现思路

# 订阅时,同步写入 Redis Set
async def subscribe(self, symbols: List[str]):
    target = self._select_connection(symbols)
    await target.ws.send(json.dumps({"cmd": "subscribe", "data": {"channel": "ticker", "symbols": symbols}}))
    await self.redis.sadd(f"pool:{self.pool_id}:subscriptions", *symbols)
    target.symbols.extend(symbols)

# 重连后,从 Redis 恢复
async def _restore_subscriptions(self, conn: WSConnection):
    symbols = await self.redis.smembers(f"pool:{self.pool_id}:subscriptions")
    if symbols:
        await conn.ws.send(json.dumps({"cmd": "subscribe", "data": {"channel": "ticker", "symbols": list(symbols)}}))
        conn.symbols = list(symbols)

设计考量:将订阅状态存在 Redis 而非内存,意味着连接池本身是无状态的——任意一个连接池实例挂掉,新启动的实例可以从 Redis 恢复订阅状态,继续工作。

3.3 行情数据写入 Redis 的三种模式

数据结构使用方式适用场景
HashHSET ticker:AAPL.US last_price 175.23 timestamp 1773302400000策略只关心最新价格,定时轮询读取
Pub/SubPUBLISH ticker_update:AAPL.US '{"last_price":175.23}'策略需要实时通知,但可接受偶尔丢失
StreamsXADD tick_stream:AAPL.US * price 175.23 volume 1200策略需要历史回放精确不漏的消息

本文实现采用 Hash + Pub/Sub 组合:Hash 保证策略随时能读到最新值(断线重连后也能拿到最新价),Pub/Sub 提供实时通知避免轮询延迟。

3.4 消息处理核心代码

import json
import asyncio
import os
from typing import Dict, Optional
import redis.asyncio as redis

API_KEY = os.environ.get("TICKDB_API_KEY")
REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379")

class MarketDataWriter:
    def __init__(self, pool_id: str = "pool-1"):
        self.pool_id = pool_id
        self.redis: Optional[redis.Redis] = None
        self._write_buffer: Dict[str, list] = {}
        
    async def start(self):
        self.redis = await redis.from_url(REDIS_URL, decode_responses=True)
        
    async def handle_ticker_message(self, data: dict):
        symbol = data.get("symbol")
        if not symbol:
            return
            
        ticker_data = {
            "last_price": str(data.get("last_price", "")),
            "timestamp": str(data.get("timestamp", "")),
            "volume_24h": str(data.get("volume_24h", "")),
        }
        
        try:
            await self.redis.hset(f"ticker:{symbol}", mapping=ticker_data)
            await self.redis.expire(f"ticker:{symbol}", 5)
            await self.redis.publish(f"ticker_update:{symbol}", symbol)
        except redis.RedisError as e:
            self._buffer_message(symbol, data)
            
    def _buffer_message(self, symbol: str, data: dict):
        if symbol not in self._write_buffer:
            self._write_buffer[symbol] = []
        self._write_buffer[symbol].append(data)
        if len(self._write_buffer[symbol]) > 100:
            self._write_buffer[symbol].pop(0)
⚠️ 工程预警:生产环境中,hsetexpire 应使用 Redis 事务或 Lua 脚本保证原子性。_buffer_message 是内存缓冲,进程重启会丢失,重要场景应落盘到本地 SQLite。

四、完整代码:MarketDataWriter 类

以下是可直接运行的 MarketDataWriter 完整实现。

import asyncio
import websockets
import json
import random
import os
import logging
from typing import List, Set, Dict, Optional
from dataclasses import dataclass, field
from enum import Enum
import redis.asyncio as redis

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

API_KEY = os.environ.get("TICKDB_API_KEY")
REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379")
WS_URL = f"wss://api.tickdb.ai/v1/realtime?api_key={API_KEY}"

class ConnState(Enum):
    IDLE = "idle"
    ACTIVE = "active"
    DEAD = "dead"

@dataclass
class WSConnection:
    conn_id: str
    state: ConnState = ConnState.IDLE
    ws: Optional[websockets.WebSocketClientProtocol] = None
    symbols: List[str] = field(default_factory=list)
    last_pong: float = 0.0

class MarketDataWriter:
    def __init__(self, pool_size: int = 4, max_per_conn: int = 20):
        self.pool_size = pool_size
        self.max_per_conn = max_per_conn
        self.connections: List[WSConnection] = []
        self._hot_spare: List[WSConnection] = []
        self.redis: Optional[redis.Redis] = None
        self._lock = asyncio.Lock()
        self._write_buffer: Dict[str, list] = {}
        self._running = False
        
    async def start(self):
        """启动连接池和 Redis 连接"""
        self.redis = await redis.from_url(REDIS_URL, decode_responses=True)
        self._running = True
        
        for i in range(self.pool_size):
            conn = WSConnection(conn_id=f"conn-{i}")
            await self._connect_with_backoff(conn)
            asyncio.create_task(self._heartbeat_loop(conn))
            asyncio.create_task(self._message_loop(conn))
            self.connections.append(conn)
            logger.info(f"连接 {conn.conn_id} 已建立")
            
        if self.connections:
            spare = self.connections.pop()
            spare.state = ConnState.IDLE
            self._hot_spare.append(spare)
            logger.info(f"热备连接 {spare.conn_id} 已预留")
            
    async def _connect_with_backoff(self, conn: WSConnection):
        retry, cap = 0, 60
        while self._running:
            try:
                conn.ws = await websockets.connect(WS_URL)
                conn.state = ConnState.ACTIVE
                conn.last_pong = asyncio.get_event_loop().time()
                logger.info(f"{conn.conn_id} 连接成功")
                return
            except Exception as e:
                delay = min(2 ** retry, cap)
                jitter = random.uniform(0, delay * 0.1)
                logger.warning(f"{conn.conn_id} 连接失败,{delay:.1f}秒后重试: {e}")
                await asyncio.sleep(delay + jitter)
                retry += 1
                
    async def _heartbeat_loop(self, conn: WSConnection):
        while self._running and conn.state != ConnState.DEAD:
            try:
                if conn.ws and conn.state == ConnState.ACTIVE:
                    await conn.ws.send(json.dumps({"cmd": "ping"}))
            except Exception:
                pass
            await asyncio.sleep(1)
            
    async def _message_loop(self, conn: WSConnection):
        while self._running and conn.state != ConnState.DEAD:
            try:
                msg = await asyncio.wait_for(conn.ws.recv(), timeout=5)
                data = json.loads(msg)
                
                # 拦截业务错误码:鉴权失败、限频、配额耗尽
                if data.get("code") in [1001, 3001, 3002]:
                    logger.error(f"{conn.conn_id} 业务错误: code={data.get('code')}, msg={data.get('message')}")
                    conn.state = ConnState.DEAD
                    asyncio.create_task(self._recover(conn))
                    continue
                    
                if data.get("cmd") == "pong":
                    conn.last_pong = asyncio.get_event_loop().time()
                elif data.get("cmd") == "ticker":
                    await self._handle_ticker(conn, data.get("data", {}))
            except asyncio.TimeoutError:
                now = asyncio.get_event_loop().time()
                if now - conn.last_pong > 5:
                    logger.warning(f"{conn.conn_id} 心跳超时")
                    conn.state = ConnState.DEAD
                    asyncio.create_task(self._recover(conn))
            except Exception as e:
                logger.error(f"{conn.conn_id} 消息循环异常: {e}")
                conn.state = ConnState.DEAD
                asyncio.create_task(self._recover(conn))
                break
                
    async def _handle_ticker(self, conn: WSConnection, data: dict):
        symbol = data.get("symbol")
        if not symbol:
            return
            
        ticker_data = {
            "last_price": str(data.get("last_price", "")),
            "timestamp": str(data.get("timestamp", "")),
        }
        if "volume_24h" in data:
            ticker_data["volume_24h"] = str(data["volume_24h"])
            
        try:
            async with self.redis.pipeline() as pipe:
                await pipe.hset(f"ticker:{symbol}", mapping=ticker_data)
                await pipe.expire(f"ticker:{symbol}", 5)
                await pipe.publish(f"ticker_update:{symbol}", symbol)
                await pipe.execute()
        except redis.RedisError as e:
            logger.error(f"Redis 写入失败 {symbol}: {e}")
            self._buffer_message(symbol, data)
            
    def _buffer_message(self, symbol: str, data: dict):
        if symbol not in self._write_buffer:
            self._write_buffer[symbol] = []
        self._write_buffer[symbol].append(data)
        if len(self._write_buffer[symbol]) > 100:
            self._write_buffer[symbol].pop(0)
            
    async def _recover(self, dead_conn: WSConnection):
        logger.info(f"开始恢复 {dead_conn.conn_id}")
        
        if self._hot_spare:
            hot = self._hot_spare.pop()
            symbols = await self._get_persisted_subscriptions()
            if symbols:
                await self._do_subscribe(hot, list(symbols))
            hot.state = ConnState.ACTIVE
            async with self._lock:
                self.connections.append(hot)
            logger.info(f"热备 {hot.conn_id} 已接管")
            
        await self._connect_with_backoff(dead_conn)
        if dead_conn.state == ConnState.ACTIVE:
            symbols = await self._get_persisted_subscriptions()
            if symbols:
                await self._do_subscribe(dead_conn, list(symbols))
            async with self._lock:
                self.connections.append(dead_conn)
            logger.info(f"{dead_conn.conn_id} 恢复成功")
            
    async def _get_persisted_subscriptions(self) -> Set[str]:
        if not self.redis:
            return set()
        return await self.redis.smembers("market_data_writer:subscriptions")
        
    async def _do_subscribe(self, conn: WSConnection, symbols: List[str]):
        await conn.ws.send(json.dumps({
            "cmd": "subscribe",
            "data": {"channel": "ticker", "symbols": symbols}
        }))
        conn.symbols = symbols
        if self.redis:
            await self.redis.sadd("market_data_writer:subscriptions", *symbols)
            
    async def subscribe(self, symbols: List[str]):
        async with self._lock:
            target = min(self.connections, key=lambda c: len(c.symbols))
            new_symbols = [s for s in symbols if s not in target.symbols]
            if not new_symbols:
                return
            if len(target.symbols) + len(new_symbols) > self.max_per_conn:
                if self._hot_spare:
                    target = self._hot_spare.pop()
                    target.state = ConnState.ACTIVE
                    self.connections.append(target)
            await self._do_subscribe(target, new_symbols)
            
    async def stop(self):
        self._running = False
        for conn in self.connections + self._hot_spare:
            if conn.ws:
                await conn.ws.close()
        if self.redis:
            await self.redis.close()
        logger.info("MarketDataWriter 已关闭")

使用方法

async def main():
    writer = MarketDataWriter(pool_size=3, max_per_conn=20)
    await writer.start()
    await writer.subscribe(["AAPL.US", "TSLA.US", "700.HK", "BTCUSDT"])
    await asyncio.Event().wait()

if __name__ == "__main__":
    asyncio.run(main())

消费者端读取示例

# 策略 A:轮询读取最新价
async def get_latest_price(symbol: str):
    r = await redis.from_url(REDIS_URL, decode_responses=True)
    data = await r.hgetall(f"ticker:{symbol}")
    return data.get("last_price")

# 策略 B:订阅实时更新
async def subscribe_updates(symbol: str):
    r = await redis.from_url(REDIS_URL, decode_responses=True)
    pubsub = r.pubsub()
    await pubsub.subscribe(f"ticker_update:{symbol}")
    async for msg in pubsub.listen():
        if msg["type"] == "message":
            price = await get_latest_price(symbol)
            print(f"{symbol} 更新: {price}")

五、踩坑记录与调优建议

5.1 五个生产环境暗坑

问题现象根因解决方案
Redis 断连数据丢失写入失败静默,策略读到旧价未处理 redis.RedisError✅ 必须捕获异常,写入本地缓冲文件;恢复后补推
行情乱序覆盖新价格被旧价格覆盖Hash 无条件写入,不检查 timestamp✅ 写入前比较 timestamp,只保留更新的数据
订阅状态不一致重连后漏订阅订阅状态仅存内存✅ 持久化到 Redis Set,重连时全量恢复
Pub/Sub 消息丢失策略没收到更新通知Pub/Sub 无持久化,订阅前消息丢失✅ 策略启动时先读 Hash 获取当前价,再订阅
Redis 内存膨胀行情 Hash 永不过期,内存持续增长未设置 TTL✅ 每条行情写入后 EXPIRE key 5
业务错误码静默连接正常但无数据服务端返回 3001/3002,客户端未处理✅ 在消息循环中拦截 code 字段并触发重连

5.2 性能调优参数速查

参数推荐值调优依据
单连接订阅上限20-30超过 30 后 P99 延迟陡升
连接池大小订阅数/20 + 1(热备)留一个热备应对突发故障
行情 Hash TTL5 秒平衡内存占用与脏读风险
Redis 连接池大小10-20匹配 asyncio 并发写入量
重连最大延迟60 秒超过则告警人工介入
本地缓冲上限100 条/标的避免内存泄漏

5.3 对比:有 Redis 共享 vs 无 Redis 各自订阅

指标各自订阅(3策略×50标的)Redis 共享总线
WebSocket 连接数3-9 个3-4 个(连接池统一管理)
断线恢复时间各自重连,最长 60 秒热备接管,<500ms
策略间数据一致性可能不一致完全一致(同源写入 Redis)
新增策略成本需新建连接,重新订阅零成本,直接读 Redis
运维复杂度高(多连接监控)低(只监控连接池和 Redis)

▍本章核心结论

  • Redis 共享总线让策略与行情源彻底解耦——策略不关心连接数、不关心重连、不关心限频。
  • 代价是 5-10ms 的写入延迟和 Redis 运维成本。对于绝大多数量化场景,这个代价完全值得。

六、结语

▍一句话记住本文

WebSocket 负责接入,Redis 负责分发,连接池负责高可用——三者组合让行情系统从“单兵作战”升级为“集团军协同”。

真正的生产级行情系统,不是“能收到数据”,而是“任何一个组件挂掉,策略都无感知”。本文的 MarketDataWriter 实现了:

  • 连接池热备:单连接故障 <500ms 切换
  • 订阅持久化:重启后自动恢复
  • Redis 共享总线:多策略零成本接入
  • 业务错误码拦截:限频/鉴权失败自动退避

在构建上述架构时,一个绕不开的工程问题是多市场异构数据源的统一接入。维护美股、港股、A 股、加密货币四个市场的独立 WebSocket 连接,意味着四套心跳逻辑、四套重连策略、四套消息解析器。工程上的实践是寻找一个能跨市场的统一网关。
本文测试环境选用了 TickDB,它通过单一 WebSocket 连接即可订阅多市场标的,心跳协议标准化为每 1 秒 ping。你也可以选择自行实现多连接聚合层,或使用其他支持跨市场的供应商——核心思路是降低连接管理的复杂度

扩展方向

本文代码已覆盖核心机制。你可以在此基础上扩展:

  • 数据持久化:将 Redis 中的行情定期落库到 ClickHouse 或 TimescaleDB,用于策略回测。
  • 多市场聚合:通过同一连接池订阅美股、港股、A 股、加密货币,统一写入 Redis 不同前缀。
  • 监控告警:暴露 Prometheus metrics,监控 Redis 写入延迟、连接池健康状态、本地缓冲堆积量。

▍零成本跑通代码:Claw Keys 免注册试用

如果你不想立即注册 API Key,TickDB 提供了面向开发者的 Claw Keys 试用机制——默认开放 72 个热门标的(覆盖 AAPL、TSLA、700.HK、BTCUSDT、000001.SZ 等),无需配置即可测试。

在 ChatGPT、Claude 或 Cursor 中输入以下提示词,让 AI 直接帮你跑通 WebSocket → Redis 链路:

读取 TickDB 官方 GitHub 仓库中的 SKILL.md 协议文件(路径:tickdb-unified-realtime-marketdata-api/SKILL/SKILL.md),利用其中的试用 Key 获取 AAPL.US 实时行情。

验证通过后,可搜索“TickDB”免费获取解锁全部品种的正式 API Key。


本文不构成任何投资建议。市场有风险,投资需谨慎。

上周同事问我,你看起来天天在敲代码,怎么效率这么高?

我说,因为我学会了正确摸鱼。
不是偷懒,是找到节奏。之前我也是死磕8小时,结果下午3点就脑子糊了,bug越改越多。

现在的节奏:
上午9-11点:干正事 这时候脑子最清醒,写核心逻辑、解复杂bug。不接会议,不看消息,手机扔抽屉。
11-12点:摸鱼时间 刷技术博客、看GitHub趋势、逛V2EX。不干活,但看的东西和工作相关。脑子在后台消化上午的问题,经常这时候突然想到解法。
下午2-4点:干正事 继续上午的活儿,或者处理邮件、开会。这时候效率一般,适合做不需要深度思考的事。
4-5点:第二次摸鱼 下楼买杯咖啡,或者站着看会儿窗外。有时候带耳机听段播客,和技术无关的,纯放松。
5-6点:收尾 整理今天写的代码,写注释,列明天todo。这时候不新开功能,避免加班。

关键发现:
之前我以为8小时连轴转是努力,后来才发现是低效。
现在每天实际深度工作时间大概4小时,产出比之前8小时还高。因为脑子清醒的时候真的在干活,糊涂的时候真的在休息。

具体技巧:

  1. 番茄钟别用25分钟,太短了,刚进入状态就打断。我用50分钟工作+10分钟休息。
  2. 下午3点必喝咖啡,不是提神,是给自己一个"下半场开始"的仪式感。
  3. 晚上不写代码,最多看看文档。晚上写的代码,第二天早上大概率要重写。
  4. 周五下午不排任务,整理一周工作,看看技术文章,准备下周计划。

老板怎么看?
我一开始怕老板觉得我在偷懒,后来发现,只要deadline不耽误,老板其实不关心你几点在敲键盘。
有一次我提前两天交了项目,老板问我怎么做到的。我说"找到了节奏",他没追问。

总结:
程序员的工作不是流水线,不是时间堆出来的。找到自己能专注的时段,其他时间该摸鱼就摸鱼,脑子反而更清醒。
当然,前提是能按时交活。如果deadline都搞不定,那还是先死磕吧。

告别“混合内容”警告:HTTPS部署后依然显示“不安全”的深层原因与修复指南

当你终于为网站配置好SSL证书,满心期待地址栏那把代表安全的“小绿锁”出现时,却发现浏览器依然显示“不安全”或“此网站包含不安全内容”。这并非SSL证书失效,而是你的网站陷入了“混合内容”的陷阱。

简单来说,混合内容是指一个通过HTTPS(加密)加载的网页,其中却包含了通过HTTP(明文)加载的子资源,如图片、脚本、样式表或API接口。这就像一辆装甲运钞车(HTTPS页面)在运送贵重物品时,却打开车窗从路边一个无人看管的货摊(HTTP资源)取东西,整个运输过程的安全性瞬间被破坏。现代浏览器为了用户安全,会主动拦截这些不安全的请求,并向你发出警告。

混合内容主要分为两类:

  1. 主动混合内容:指能够执行代码或修改页面内容的资源,如JavaScript脚本、CSS样式表、iframe、AJAX/Fetch请求等。由于其高风险性,浏览器会直接阻止其加载,可能导致网站功能失效或布局错乱。
  2. 被动混合内容:指仅用于展示的资源,如图片、音频、视频等。虽然风险相对较低,但浏览器仍会发出警告,地址栏的“小绿锁”会消失或变为灰色警告标志,严重影响用户信任度。

第一步:精准定位“病灶”

在动手修复前,必须先找到所有不安全的资源。浏览器开发者工具是你的最佳帮手。

  1. 打开你的HTTPS网站,按F12键调出开发者工具。
  2. 切换到“Console”(控制台)面板,刷新页面。
  3. 仔细查找红色的错误信息,通常会包含“Mixed Content”字样,并明确指出是哪个HTTP资源被阻止或发出了警告。
  4. 你也可以切换到“Security”(安全)面板,这里会更清晰地列出所有不安全的请求及其类型。

第二步:分而治之,对症下药

找到问题后,根据资源的类型和可控性,采取不同的修复策略。

对于可控资源(最彻底的方案)

这类资源包括你网站自身的图片、CSS、JS文件以及后端API接口。

  1. 显式替换为HTTPS:这是最直接、最可靠的方法。全面扫描你的HTML、CSS、JavaScript代码,将所有硬编码的http://开头的URL,全部替换为https://。例如,将<img src="http://example.com/logo.png">改为<img src="https://example.com/logo.png">
  2. 使用协议相对URL:对于某些第三方资源,如果你不确定其是否稳定支持HTTPS,可以使用协议相对URL。这种方式省略了协议部分,让浏览器自动继承当前页面的协议。例如,将<script src="http://cdn.example.com/lib.js"></script>改为<script src="//cdn.example.com/lib.js"></script>。当页面是HTTPS时,浏览器会自动请求https://cdn.example.com/lib.js

对于不可控资源(最优雅的兜底方案)

很多时候,混合内容来自你无法修改的第三方服务,如某些旧的统计代码、广告联盟或CDN资源。此时,手动修改不现实,我们需要一个更聪明的办法。

启用内容安全策略(CSP)的upgrade-insecure-requests指令

这是一个“一键升级”的神器。你只需在服务器响应头或HTML页面的<head>标签中加入一条指令,浏览器就会自动将页面内所有的HTTP请求升级为HTTPS请求。

在Nginx服务器配置中,只需在server块里添加一行:
add_header Content-Security-Policy "upgrade-insecure-requests";

在Apache服务器的.htaccess文件中,添加:
Header set Content-Security-Policy "upgrade-insecure-requests"

如果无法修改服务器配置,也可以在HTML的<head>部分加入<meta>标签:
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

重要提示:此方案的前提是,那些HTTP资源对应的服务器也必须支持HTTPS访问。如果对方服务器不支持,强制升级会导致资源加载失败。

第三步:巩固防线,防患未然

修复了现有问题后,还需要建立长效机制,防止混合内容再次出现。

  1. 配置HTTP到HTTPS的强制重定向:确保所有通过http://访问的请求都被301永久重定向到https://。这可以从根源上减少HTTP链接的产生。在Nginx中,可以配置一个80端口的server块,使用return 301 https://$host$request_uri;实现。
  2. 启用HSTS(HTTP严格传输安全) :HSTS是一个更强大的安全策略。它通过响应头Strict-Transport-Security告诉浏览器:“在未来的一段时间内,访问我这个域名,必须无条件使用HTTPS。”这可以有效防止SSL剥离攻击,并避免用户因手动输入http://而触发重定向。
  3. 建立开发规范:在前端开发中,严禁硬编码协议。应使用环境变量或配置中心来管理API基地址等资源链接,确保开发、测试、生产环境的协议能自动适配。

HTTPS的部署不是一劳永逸的终点,而是一个持续优化的过程。混合内容问题是这个过程中最常见的挑战之一。通过精准定位、分层修复和建立防御机制,你不仅能消除浏览器的警告,更能为用户构建一个真正安全、可信的访问环境,让那把“小绿锁”名副其实

在网络业务开展中,代理IP是保障访问稳定的重要工具。然而实际使用时,不少用户仍存在代理IP被网站识别的问题,从而影响业务推进。

IP类型的本质差异

代理IP的类型从根本上决定了其被识别概率的高低。如由正规运营商分配的住宅代理,源自真实家庭宽带。而多数被识别的代理 IP,多为数据中心IP,这类IP集中归属机房、云服务厂商,IP段特征明显,网站通过IP地址库即可快速判定。

数据中心IP常被纳入平台风险名单,即便请求正常,也易因“出身”被标记,这是代理IP被识别的首要根源。

IP信誉与历史行为

代理IP的使用历史会累积形成信誉记录。若某个代理IP此前被大量用户用于高频访问、异常请求或触发过网站的安全机制,该IP便会被标记为低信誉地址。

网站通常维护内部的风险IP库,对历史行为不佳的代理IP实施限流或拒绝服务。即便当前使用者并无异常操作,该IP仍因过往记录而遭受限制,这一累积效应在共享型代理服务中尤为明显。

协议与类型

不同业务场景对网络协议的需求存在差异,选择适配的代理协议类型至关重要。HTTP代理适用于Web流量转发,适合网页数据获取等场景;而SOCKS5协议支持TCP与UDP等多种传输方式,可承载包括邮件服务、实时通信在内的更广泛网络应用。

两者在数据封装格式以及协议扩展性上存在明显差异。若协议选择与业务场景不匹配,则可能导致请求被拒绝或触发网站的识别机制。因此,选择合理的代理协议,是降低识别风险、保障访问成功率的重要环节。

此外,代理IP仅为一种中立的网络工具,使用者应遵守目标网站的服务条款及相关法律法规,在合法范围内开展业务。合规使用不仅是维护IP信誉的基础,也是保障代理服务长期稳定运行的前提。

总结

代理IP被识别是IP类型、历史信誉与协议合规等多重因素共同作用的结果。了解这些识别机制,有助于从业者从代理选型与配置层面优化方案,提升业务开展的稳定性。

一、 禅道:国产全生命周期管理的性价比标杆

禅道作为国内项目管理软件的常青树,在2025年依然保持着强劲的竞争力。其核心优势在于“一站式”解决了研发团队的痛点,以极具竞争力的成本提供了企业级的功能服务,是降本增效的典型代表。
1. 全生命周期管理闭环
禅道最卓越的板块在于其​核心管理流程的全覆盖​。它不仅仅是一个任务分配工具,更是一个集产品管理、项目管理、质量管理(QA)、文档管理于一体的综合平台。这种设计打破了部门间的“数据烟囱”,从需求提出到产品发布,每一个环节都在系统内留痕。对于企业而言,这意味着无需购买多套零散工具,极大地降低了软件采购与维护的隐性成本。
2. 精细化权限与安全控制
在数据安全日益重要的当下,禅道提供了​极高颗粒度的权限管理体系​。管理员可以精确控制不同角色、不同部门对项目、模块甚至字段级别的访问权限。这种“按需分配”的机制,不仅保障了核心商业机密的安全,也避免了因权限混乱导致的误操作风险,从而降低了管理纠错的内耗成本。
3. 高性价比的私有化部署
禅道在成本控制上给予了企业最大的诚意。其开源版本功能已经相当完善,支持​企业进行私有化部署​,数据完全掌握在企业自己手中。这对于数据敏感型或预算有限的中小企业来说,是极佳的“降本”方案。即便是企业版,相比国际同类产品,其授权费用也更为亲民,且提供原厂技术支持,大幅降低了后续运维的人力投入。

二、 Jira:全球敏捷研发的“硬核”引擎

Jira依然是全球软件开发领域的行业标准,其强大的扩展性与敏捷支持的深度,使其成为大型技术团队不可或缺的生产力工具。
1. 强大的工作流引擎
Jira的核心壁垒在于其​高度可配置的工作流系统​。团队可以根据自身的开发模式(如Scrum或Kanban),设计出极其复杂的任务流转逻辑。每一个状态变更、每一个条件判断都可以被系统捕捉并执行相应动作。这种严谨的逻辑确保了研发流程的标准化,从源头上减少了因流程随意导致的返工浪费。
2. 敏捷开发深度支持
对于追求快速迭代的团队,Jira提供了​原生的敏捷看板与报表​。燃尽图、速率图等敏捷指标一应俱全,帮助团队实时复盘迭代效率。通过数据驱动的方式,管理者可以精准识别开发过程中的瓶颈,优化资源配置,实现研发效能的持续提升。
3. 庞大的插件生态系统
Jira拥有业界最丰富的​插件市场​。无论是代码集成、自动化测试还是服务台支持,企业都可以通过安装插件来扩展功能。这种“搭积木”式的架构,使得Jira能够适应企业不同发展阶段的需求,避免了频繁更换系统带来的迁移成本,是一项长期可靠的资产。

三、 Microsoft Project:经典项目控制的“定海神针”

对于工程、制造等传统行业,Microsoft Project(MS Project)凭借其无可替代的计划编制能力,依然是复杂项目管理的首选权威工具。
1. 专业的甘特图与排程引擎
MS Project拥有业界最强大的​甘特图计算引擎​。它支持关键路径分析、资源平衡以及复杂的任务依赖关系设定。在超大型项目中,人工排程几乎不可能,而MS Project能通过算法自动优化工期,避免资源冲突,确保项目按时交付,这是最大的“增效”。
2. 精细化资源与成本管理
区别于轻量级工具,MS Project在资源与成本核算方面做到了极致。管理者可以录入人员工时费率、材料成本,系统会自动汇总项目预算与实际消耗。这使得项目管理从单纯的“管事”上升到“管钱”,为企业提供了精准的成本控制依据。
3. 无缝的Office生态集成
MS Project与​Office 365生态深度融合​。项目计划可以直接发布到SharePoint,任务同步至Outlook,报表导出至Excel。对于习惯了微软办公套件的企业来说,这种无缝集成极大地降低了学习成本和沟通门槛,让团队协作更加顺畅。

四、 Asana:以人为本的团队协作中枢

Asana以其简洁优雅的界面和人性化的交互设计,成为市场、运营及创意团队提升协作效率的利器。
1. 多维度视图自由切换
Asana允许用户在同一项目中​一键切换列表、看板、时间轴和日历视图​。这种设计照顾到了不同角色的关注点:项目经理看时间轴把控进度,执行人员看列表聚焦待办。灵活的视图切换减少了信息筛选的时间,让每个人都能快速找到自己的工作重点。
2. 智能任务依赖与提醒
项目延期往往是因为上下游衔接不畅。Asana提供了​直观的任务依赖设定​,当上游任务延期时,系统会自动通知下游负责人。此外,其智能提醒功能会根据截止日期主动推送消息,避免了人工催办的尴尬与低效,让团队协作如齿轮般精密咬合。
3. 目标与战略对齐
Asana不仅关注任务执行,更引入了​Goals(目标)模块​。团队可以将日常任务与公司的年度战略目标关联。这种“所见即所得”的目标对齐机制,让员工清晰感知工作价值,避免了“为了做任务而做任务”的低效忙碌,从精神层面提升了团队产出。

五、 Monday.com:可视化工作流的高效创新者

Monday.com以其极具视觉冲击力的界面和高度自定义的特性,重新定义了项目管理的用户体验,让工作变得透明且有趣。
1. 高可视化的状态管理
Monday.com将枯燥的表格变成了​色彩丰富的可视化看板​。通过不同颜色的状态列、进度条,项目健康状况一目了然。管理者无需翻阅详细报告,仅凭颜色即可判断风险点。这种可视化的设计大大缩短了信息获取时间,提升了管理决策效率。
2. 强大的自动化配方
为了减少重复性劳动,Monday.com内置了​丰富的自动化配方​。例如“当状态变为完成时,自动通知项目经理”。用户无需懂代码,只需简单配置即可实现流程自动化。据测算,这些自动化流程能为团队节省大量手动操作时间,直接体现为人力成本的降低。
3. 跨部门协作看板
Monday.com打破了部门壁垒,支持构建​跨职能的工作看板​。销售、市场、研发可以在同一个平台上共享进度,数据实时同步。这种透明的协作机制消除了信息不对称带来的沟通成本,加速了业务流转。

六、 Trello:极简看板管理的效率先锋

Trello是看板管理方法的忠实实践者,以其极简的操作逻辑,成为无数小微团队和个人项目管理的首选。

1. 直观的拖拽式看板

Trello的核心是**“看板-列表-卡片”三层结构。操作极其简单,用户只需拖拽卡片即可更新任务状态。这种符合直觉的交互设计,让新团队成员上手时间几乎为零,极大降低了培训成本。

2. 灵活的Power-Up插件体系

虽然本体简单,但Trello通过Power-Up插件赋予了其无限可能。无论是接入Google Drive文件,还是开启投票功能,团队都可以按需加载。这种“按需付费”的模式,避免了为不需要的功能买单,是极致的“降本”思维。

3. 团队沟通透明化

Trello将讨论、附件、检查清单**全部集中在卡片内。所有关于任务的沟通都有迹可循,避免了信息散落在微信、邮件等不同渠道。这种“任务即沟通”的模式,确保了信息的完整性,减少了反复确认的时间浪费。

七、 Smartsheet:电子表格的企业级进化

Smartsheet巧妙地结合了电子表格的易用性与企业级项目管理的强大功能,是习惯Excel管理的团队转型的最佳选择。
1. 熟悉的表格界面与增强功能
Smartsheet采用了用户​极度熟悉的电子表格UI​,上手零门槛。但在表格之下,它隐藏了甘特图、附件、提醒等项目管理能力。这种设计让企业在不改变操作习惯的前提下,享受到了专业工具的红利,转型成本极低。
2. 行级附件与证明管理
在审批流程中,Smartsheet的行级附件功能尤为实用。每一行任务都可以挂载合同、发票等凭证,审批人可直接查看。这种将文档与数据深度绑定的方式,解决了传统管理中“数据与资料分离”的痛点,提升了审核效率。
3. 企业级安全与合规
对于大型企业,Smartsheet提供了​完善的安全管控体系​,包括审计日志、权限分级等。它符合SOC等国际安全标准,确保了企业在享受便捷的同时,数据资产得到严密的保护。

八、 ClickUp:一站式生产力平台新贵

ClickUp以“一个应用替代所有应用”为愿景,集成了任务、文档、目标、聊天等功能,适合追求极致效率的工具控团队。
1. 多层级层级结构
ClickUp设计了独特的​Space-Folder-List-Task层级结构​,能够完美适配从公司战略到个人待办的各种颗粒度。这种层级化的管理帮助团队在复杂的业务中理清脉络,避免了任务混乱导致的管理失控。
2. 文档与任务一体化
ClickUp内置了​强大的文档系统​,支持在文档中直接插入任务、创建看板。团队可以在撰写方案的同时,将其转化为可执行的任务,实现了从策划到执行的无缝衔接,减少了工具切换带来的注意力分散。
3. 高度自定义字段
ClickUp允许用户​自定义各种字段类型​,如货币、评分、进度等。这使得ClickUp能够模拟出CRM、Bug追踪系统等多种工具的形态,真正实现了“一物多用”,为企业节省了购买其他垂直软件的费用。

九、 Zoho Projects:高性价比的SaaS全能选手

作为Zoho全家桶的重要一员,Zoho Projects凭借高性价比和强大的集成能力,成为中小企业数字化转型的稳健之选。
1. 智能甘特图与规划
Zoho Projects提供了​交互式的智能甘特图​,支持自动排程和关键路径识别。当项目计划发生变更时,系统能智能调整后续任务,帮助管理者轻松应对变化,确保项目如期交付。
2. 深度集成Zoho生态
如果企业使用Zoho CRM或Books,Zoho Projects将展现出​巨大的生态优势​。项目数据可与客户信息、财务账单打通,实现从商机到交付再到回款的全流程数字化闭环,极大提升了业务流转效率。
3. 自动化规则与蓝图
通过​蓝图功能​,Zoho Projects帮助企业规范业务流程。管理者可以可视化地定义任务流转规则,确保标准作业程序(SOP)在团队中严格执行,减少了因人员能力差异导致的质量波动,实现了管理复制的“增效”。

2025 年 12 月 13 日,VeloxCon China 2025 在北京成功举办。作为 Velox 项目首次在中国举办的线下技术大会,汇聚了来自Meta、IBM、蚂蚁集团、阿里云、腾讯、小米、小红书等企业的数十位核心贡献者与一线工程师。

大会通过 18 场演讲将 Velox 置于真实业务场景之中,系统展示了其在架构演进、AI 数据处理、湖仓加速、流批融合等方向的最新实践。这些分享不仅直面性能、稳定性与兼容性等落地挑战,也反应了开发者社区对构建可靠、可扩展、可协同的数据基础设施的共同探索,彰显了中国开发者在全球高性能分析生态中的工程深度与协作广度。

夯实底座,突破能力边界
会议伊始,Velox 项目联合发起人 Pedro 发表开幕致辞。他回顾了 Velox 开源项目的发展历程,从项目启动、开源发布到建立技术治理结构,展示了 Axiom 架构、GPU 支持、PyVelox 等关键进展,强调了社区协作与工程严谨性是项目持续演进的核心动力。他特别提到,Velox 已建立了正式的技术治理机制,并迎来来自 IBM、Intel、NVIDIA、Microsoft 等多家企业的新增维护者,标志着项目正迈向更加开放和可持续的阶段。

在明确了社区与架构演进的总体方向后,大会议题迅速深入到如何利用 Velox 构建高性能计算引擎的具体实践中。阿里云 EMR Serverless Spark 技术负责人周克勇系统阐述了“可组合性”在数据计算领域的实践。他详细解析了阿里云如何深度集成并贡献于 Apache Celeborn、Paimon、Velox 及 Gluten 等开源组件,通过模块化组装构建出高性能湖仓一体引擎。他指出,基于该架构,阿里云 EMR Serverless Spark 成功创造了 TPC-DS 100TB 规模性能测试的世界新纪录,实现性能翻倍与性价比大幅提升。

接着,Meta 软件工程师 Masha Basmanova 阐述了现有查询引擎在跨语言通信、优化器能力与开发体验上面临的挑战,并介绍了基于 C++ 的统一前端框架 Axiom。该框架将 SQL 解析、逻辑优化与物理执行融为一体,通过内置的强大优化器与 Velox 运行时无缝对接,能够实现更高效、可扩展的查询处理。演讲最后,她积极展示了 Axiom 的开源路线图,并欢迎全球开发者加入,共同推动该项目的演进。

强大的执行框架,最终需要服务于极具挑战性的数据场景,特别是爆发式增长的 AI 数据。Meta 软件工程师孟晓烜则在之后的演讲中,深入阐述了应对AI训练数据规模激增与成本挑战的解决方案。他重点介绍了 Meta 如何通过数据归一化技术剥离重复特征,并构建可索引的序列存储系统。依托 Velox 技术栈,团队在训练数据的加载、生成与探索三大环节实现了端到端优化,显著提升了处理效率与资源利用率。

在 Meta 多位工程师从框架演进、可组合架构、数据标准化等角度深入分享后,蚂蚁集团高级技术专家黄叶伟也从企业落地实践层面分享了基于 Velox 的 Spark 加速实践。他重点介绍了基于 Gluten 与 Velox 构建的向量化引擎如何通过任务级 Fallback、Spill 优化、Shuffle 优化等关键技术,在混合部署场景下显著提升 Spark 性能与稳定性。他表示,该方案目前已实现日均数十万任务覆盖,平均节省资源超30%,并将在算子优化与架构扩展方面持续演进。

作为连接 Spark 生态与原生加速的关键中间层,Apache Gluten 的进展同样备受关注。来自 IBM 的莫芮与周渊聚焦 Apache Gluten与 Velox 的深度集成,阐述了其如何在大数据分析中驱动创新。他们介绍,Gluten 在保持对 Spark/Flink 作业透明加速能力的同时,正逐步增强对多后端引擎和复杂业务场景的适配能力。目前,该方案已在 Pinterest、顺丰科技及多个内部集群完成规模化验证,有效支撑了从日志分析到物流调度等多样化负载的性能提升与成本优化。

随着向量化加速在通用场景日趋成熟,针对特定存储格式的深度优化成为新的效能突破口。腾讯大数据开发工程师陈锦海分享了微信基于 Velox 加速 lceberg 湖仓分析的优化与实践,重点介绍了原生分桶方案。据他介绍,该方案通过动态识别表元信息自动设置分区数,能有效缓解 AQE 引发的写入倾斜,结合空闲资源灰度发布策略,可保障大规模作业的稳定上线。

扎根场景,释放协同效能
午餐后的议程更加聚焦 Velox 在真实业务中的集成深度与生产韧性,回应了开发者们对兼容性、稳定性与端到端效能等规模化落地的核心关切。
小米计算平台计算引擎负责人王胜杰分享了公司在 Spark 向量化升级中的规模化落地经验。面对业务迁移中的兼容性与稳定性挑战,他表示,小米通过自动兼容校验、双跑结果比对及内存异常感知的三级资源升级机制,已成功推动向量化改造在数十万作业中平稳落地。

面对海量数据挑战,全球科技公司也在探索相似的演进路径。Meta 软件工程经理 Stanley Yao 在演讲中分享了公司基于 Velox 推进 Spark 向量化改造的整体策略。他表示,团队通过从定制化方案到开源架构的持续演进,已实现关键业务管线向 Gluten(Flare)的平稳迁移,并获得显著的效率提升。未来,Meta 计划进一步扩大该架构的应用规模。

在 CPU 向量化趋于普及的同时,利用异构硬件挖掘更高性能成为新的前沿。IBM 研究院资深软件工程师 Zoltán Arnold Nagy 展示了基于 Velox 与 Presto 的 GPU 加速数据处理方案。他介绍道,Velox 通过与 cuDF 集成,可在 GPU 上高效执行算⼦,并针对多 GPU 分布式场景优化通信与数据交换。此外,为突破 I/O 瓶颈,团队正在探索结合 GPUDirect 存储与缓存层的加速策略。

对性能与稳定性的追求,也驱动着查询引擎架构本身的融合与创新。Meta 软件工程师谭家梁与大家分享了 Native Presto-on-Spark 的规模化应用。该架构以 Presto 查询优化、Spark 资源调度与容错机制以及 Velox 原生向量化执行为核心,实现了性能与可靠性的显著提升。他表示,目前该方案已在生产环境中取得成效,并将在未来持续推进全栈原生化演进。

对于国内庞大的云上业务,Velox 同样在支撑着关键数据服务平台。 阿里云高级工程师王彬与范阿冬系统介绍了Velox在阿里云日志服务中的深度集成与应用。他们指出,基于 Velox 构建的高性能查询引擎,通过混合执行、表达式下推、自动增量物化视图及免 Schema 分析等核心技术,可显著提升平台在处理海量实时数据时的查询效率与资源利用率。他们还强调,该架构不仅为日志分析、智能运维等场景提供了稳定支撑,也为面向 AI 的云原生数据平台演进奠定了坚实基础。

除了通用的日志与湖仓分析,Velox 也在向更垂直的时序数据场景渗透。腾讯高级工程师李兆龙分享了基于 Velox 构建云原生时序数据库的落地经验。他表示,通过在 Velox 中实现时序数据去重优化与存储写入增强,系统在应对高频写入与实时查询场景时,可显著提升吞吐效率与响应性能。目前该方案已有效支持物联网、实时监控等业务场景,未来还将进一步完善缓存与压缩机制,持续优化时序数据处理的整体效能。

IBM 软件工程师刘平接着分享了 Velox 在 Iceberg 数据写入能力上的突破性进展。他表示,目前 Velox 对 Iceberg 的支持以读取为主,其写入功能的完善将填补该方向的关键能力空白,为基于 Presto 与 Spark 的数据湖架构提供更统一、高效的数据摄入层。这一进展也标志着 Velox 正从查询加速向数据全链路处理拓展。

接着,来自阿里云的毕岩与周滔分享了 Velox 与 Apache Paimon 深度集成的解决方案,为提升引擎与存储的协同效率提供了另一种集成思路。在他们看来,现有方案存在表类型支持受限、缺乏可移植性等瓶颈, 但可以建立 C++ 原生 Paimon 库,通过其统一的数据协议与插件化设计,使 Paimon 能够被 Velox、StarRocks 等多种计算引擎直接高效调用,从而提升数据读写性能,并为湖仓格式的跨引擎协同提供新的基础支撑。

在批处理场景之外,流计算框架的向量化也正成为新的热点。蚂蚁集团技术专家刘勇介绍了基于 Velox 为 Flink 构建的统一向量化执行引擎 Flex。他表示,Flink 作为流批一体架构的核心,其原生向量化能力的补足至关重要。Flex 通过将 Velox 的高性能算子能力引入 Flink,同时结合自动化验证、可视化计划与精细化回退机制,现已实现了作业性能的显著提升,并支撑多条核心业务链路平稳运行。

随着 Velox 赋能的应用场景日益广泛和复杂,确保其在不同引擎和版本间的整体质量与可靠性变得至关重要。Meta 软件工程师 Eric Liu 阐述了在 AI 数据基础架构下,保障 Velox 多引擎版本可靠性的系统化方法。他指出,面对不同引擎与存储格式交织带来的复杂性,关键在于建立跨引擎测试框架与合成数据工厂。这一实践能有效提前发现全栈潜在问题,从而确保底层变更在大规模生产环境中的稳定与高效。

针对向量化引擎中窗口运算符内存溢出的典型难题,来自英特尔的贾柯分享了她的见解。她认为,通过为 Velox 引入流式窗口处理机制,可使计算随数据到达逐步执行并即时释放内存,从而从架构层面化解多数场景下的内存风险,显著提升复杂查询的稳定性。

最后,小红书 Native Engine 团队技术负责人魏秀利也分享了向量化引擎在公司业务中规模化落地的经验。据他介绍,通过将写入异步化并构建原生 Avro 读取能力,小红书在不增加业务复杂度的前提下,成功缓解了端到端延迟,印证了“执行与存储协同优化”在湖仓场景中的关键价值。

从底层执行引擎的持续创新,到日志分析、湖仓写入、流批融合等复杂场景的稳定运行,在本届 VeloxCon China 上,我们看到 Velox 的技术价值已在真实业务中不断被验证和拓展。同时我们也很高兴看到中国开发者成为这一进程的重要推动者。期待未来有更多志同道合者加入 Velox 开源社区,共建高性能分析基础设施。weibo.com/ttarticle/p/show?id=2309405289944930713617 weibo.com/ttarticle/p/show?id=2309405289945274384458 weibo.com/ttarticle/p/show?id=2309405289945618579474 weibo.com/ttarticle/p/show?id=2309405289946168033345 weibo.com/ttarticle/p/show?id=2309405289946511966256 weibo.com/ttarticle/p/show?id=2309405289946860093485 weibo.com/ttarticle/p/show?id=2309405289947204026388 weibo.com/ttarticle/p/show?id=2309405289947552153602 weibo.com/ttarticle/p/show?id=2309405289948042625029

当用户访问你的网站时,屏幕上赫然出现“SSL握手失败”或“ERR_SSL_PROTOCOL_ERROR”——几十秒的转圈后,页面拒绝加载。用户直接流失,而你可能连问题出在哪里都不知道。

所谓SSL握手,就是用户浏览器(客户端)与你的网站服务器之间的一次“加密握手”,双方就通信协议版本、加密套件、证书身份达成一致,才会真正建立HTTPS连接。这个环节一旦卡住,用户永远看不到你的网站内容。

真相一:证书过期、不完整或域名对不上

这是最冤大头的问题。很多网站管理者买了SSL证书,安装后就不管了,结果证书悄悄过期了都不知道。还有的人下载证书时只拿了服务器证书,忘了把中间证书链一起配置上去,导致浏览器无法验证证书的合法性。更常见的错误是,证书绑定的域名和你当前访问的域名不一致——比如证书是 www.abc.com,用户访问的却是 abc.com,握手一样会失败。

真相二:客户端与服务器的“语言”不统一——TLS版本冲突

每个浏览器和操作系统支持的TLS协议版本都不一样。老旧设备可能只懂TLS 1.0或1.1,而如今大多数安全网站已禁用这些过时版本,只允许TLS 1.2及以上。当一台老旧的Windows 7电脑配上旧版浏览器访问你的网站时,双方找不到一个共同支持的版本,握手自然失败。

真相三:服务器系统时间“穿越”了

这是一个容易被忽略的物理问题。SSL证书有明确的有效期起止时间,而浏览器判断证书是否有效,依赖的是客户端和服务器各自的系统时钟。如果你的服务器时间比真实时间慢了半小时,或者快了一整天,证书就可能被判定为“尚未生效”或“已过期”。明明刚买的证书,却因为时间错位而拒连,实在冤枉。

真相四:中间设备“好心办坏事”

很多网站架构中都有反向代理、负载均衡器、Web应用防火墙或CDN。这些设备会代替源服务器与客户端进行SSL握手。如果源服务器与这些中间设备之间的证书配置不一致,或者中间设备自身的TLS版本设置过于苛刻,握手请求就会在半路被截断。更麻烦的是,这类故障往往只在特定网络环境下出现,排查起来非常困难。

告别拒连:选对证书、配好服务才是根本

以上所有问题的核心,都指向一件事:你需要一张可靠、兼容性好、配有专业支持的SSL证书。选择正确的服务商JoySSL,提供国内一线品牌的SSL证书,涵盖单域名、多域名、通配符证书,同时配有专业的配置指导。无论你是遇到握手失败、证书不匹配,还是不知道如何部署中间证书,我们的工程师都能帮你一步步搞定,全程无需你敲一行代码

JeecgBoot AI专题研究 | andrej-karpathy-skills:给 AI 编程立规矩,外加一分钟安装指南

一个反常识的 GitHub 现象

最近 GitHub 趋势周榜的第一名,不是新框架,也不是新模型,而是一份不到 70 行的 Markdown 文件——项目名叫 andrej-karpathy-skills,一周拿下 4.5 万星,到目前已经累计 62.2k+。

andrej-karpathy-skills GitHub 截图

它没有复杂的代码,核心就是一个 CLAUDE.md,用来给 Claude Code、Cursor 这类 AI 编程工具立规矩,治一治它们乱写代码的毛病。

Karpathy 的吐槽,和它的起源

项目的灵感来自 Andrej Karpathy(前特斯拉 AI 负责人、OpenAI 创始团队成员)一月份在 X 上发的一条长推,阅读量逼近 800 万。他把自己用 AI Agent 写代码遇到的坑总结了一遍,几句话让无数开发者拍案:

模型会代你做错误假设,然后不假思索地执行。它们不管理自身的困惑,不寻求澄清,不呈现矛盾,不展示权衡。

它们真的很喜欢把代码和 API 搞复杂,堆砌抽象概念,不清理死代码……明明 100 行能搞定的事情,非要实现成 1000 行的臃肿架构。

它们有时仍会改动或删除自己理解不足的代码和注释,即使这些内容与任务本身无关。

开发者 Forrest Chang 把这些吐槽翻译成了模型能执行的规则,压缩成四条原则,写进了 CLAUDE.md。就这么一份文件,成了本周最火的开源项目。

四条核心原则

1. 编码前思考(Think Before Coding)

遇到歧义必须先问、先呈现权衡,而不是默不作声地猜需求。

2. 简洁优先(Simplicity First)

坚持最小可行实现:不加未请求的功能,不做一次性抽象。50 行能写完,绝不写 200 行。

3. 精准修改(Surgical Changes)

只改必须改的地方。不允许借"顺手优化"之名 reformat 相邻代码。每一行改动都能追溯到用户的原始请求。

4. 目标驱动执行(Goal-Driven Execution)

把"修复 Bug"改成"先写一个能复现 Bug 的测试,再让它通过"——可验证的目标,而不是模糊的命令

四条加起来,就把 AI 编程需要的纪律压缩进了模型能直接读懂的规则集。

快速安装(一分钟搞定)

项目提供了两种安装方式,取决于你用的是 Claude Code 还是其他工具。

方式一:Claude Code 插件(推荐)

Claude Code 用户直接用插件市场安装,两条命令即可:

# 1. 添加 marketplace
/plugin marketplace add forrestchang/andrej-karpathy-skills

# 2. 安装 skill
/plugin install andrej-karpathy-skills@karpathy-skills

安装完成后,skill 名字会变成 andrej-karpathy-skills:karpathy-guidelines,在你写代码、审代码、重构时自动激活,把四条原则注入到 Claude 的行为底盘里。

方式二:手动粘贴 CLAUDE.md(通用)

不用插件、或者用的是 Cursor / 其他 AI 工具,就直接把仓库里的 CLAUDE.md 拷到项目根目录:

# 项目根目录执行
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md

Cursor 用户把同样的内容粘到 .cursorrules 即可——这套规则本身是跟具体工具解耦的。

装完随便开一个新任务,你会明显感觉到:AI 不再乱铺抽象,不再顺手 reformat 代码,遇到歧义会先停下来问你。

实战感受

用过的开发者反馈大致一致:

  • 长任务成功率明显提升,因为 Agent 不再"想到哪写到哪"
  • 代码体积变小,AI 不再热衷堆抽象层
  • code review 压力骤降,每次改动都更聚焦
  • 轻微副作用:琐碎任务会因为多一步"先确认"而稍微变慢,可以接受

本质上它是一份高级提示词规则集,效果仍依赖底层模型的指令执行力——配 Claude 4.7 和配某些开源 7B 模型差距巨大。它解决的是"行为问题",不是"工程问题";权限、沙箱、测试基础设施这些仍得自己搭。

结语

andrej-karpathy-skills 的爆火不是一次"奇迹",而是一次极其精准的翻译——把 AI 大神对 Agent 乱象的吐槽,翻译成了模型能照着执行的纪律。

在 AI 编程逐步成为主流工作流的今天,懂得给 Agent 立规矩的人,可能比会写 Agent 的人更有竞争力。如果你今天还在被 AI 工具"乱改一通"的副作用折磨,花一分钟把它装上,立刻能感受到"管教过的 AI"和"野生 AI"的差距。

项目地址:https://github.com/forrestchang/andrej-karpathy-skills


本文为 JeecgBoot AI 专题研究系列文章。

今天通过 OCBC 充值 OpenAI API, 账单地址填的 OCBC 的地址,结果被扣了 9%的 GST 税,问下大家是不是应该用美国地址? 9%还不如用 OpenRouter 划算。

广东湛江的冬天最多也就是湿冷,套件羽绒服就能对付。东北不一样,东北的冷是物理穿透,屋里的热是魔法攻击。

我坐在老丈人家的火炕上,空气干得我直想流鼻血。电视机开着,没人看,纯粹当个白噪音。我媳妇在旁边剥砂糖橘,皮扔了一桌子。

失业一年多了。从 24 年那阵子被裁,到现在,一直就这么飘着。

以前总觉得前端这碗饭能吃挺久。每天对着电脑调像素,搞交互,为了一个组件的复用性跟产品经理吵个脸红脖子粗。后来 AI 出来了。一开始大家还当个高级玩具,没过多久,只要把需求喂进去,它写的页面结构比我都干净,连 CSS 动画都给你安排得明明白白。

前端没了。没得挺突然,但也挺理所当然。

最扯的是,就在这最没底气、最不知道明天该干嘛的节骨眼上,我结了婚,还跟着媳妇回了这趟东北老家过年。

没收入的成年人在亲戚堆里是习惯性隐身的。我尽量少说话,多干活。帮着端盘子,拿碗。

东北的年夜饭硬菜多,铁锅炖、杀猪菜,但那天晚上,我吃得最多的是白米饭。

那是老丈人自己种的,胜利村的米。没有超市里那种乱七八糟的抛光打蜡,煮出来就是单纯的饭香。米粒泛着油光,嚼在嘴里有点弹牙,咽下去带点回甘。

突然觉得挺魔幻。大城市的代码写不下去了,写字楼里的工位被机器顶了,结果跑到这冰天雪地的东北,吃着老丈人种的饭,顺手接了个人生的新“需求”。

生活没给我发什么转行的武林秘籍,我也还是不知道以后长久的路怎么走。但至少,饭还得一口一口吃,事还得一件一件做。

IMG_4674.HEIC

当起了东北的女婿,也想聊聊南北的差异:

一开始对东北有一定的滤镜,以为东北人都是热情大老伙,受小时候看的电视剧《东北一家人》以及东北雨姐影响,原来也有媳妇他爸这种老老实实,不喜欢在大伙面前说话的,他爸那边家人都是这类型性格,媳妇他妈刚好是能一直说话的那种,能量真足,我媳妇刚好处于中间,东北人说话有时候就跟捧梗一样,贼逗,跟小品一样,怪不得春晚收视率东北独占前列。

东北真是基本独生子女,地位极高,不像我粤西一家基本三个娃以上,你能读的得上书就供你,读不了拉倒。

东北的坟墓都在地里,几个小土堆,立个碑,不像粤西还得坟琢,水泥,后山碑,我问清明节咋过,他们不过,就是过年去扫一下烧纸,蜡烛都不在坟里烧,就只烧纸,媳妇她奶过年都只在十字路口写上奶她妈的名字直接烧。

我媳妇是山东闯关东去的东北,刚好落在哈尔滨五常,那边的地真大,屯子和镇的房子真的查重率 80%,街道屋子都一样,他们过年喜欢挂彩灯,南方很少挂吧,至少在粤西,他们挂彩灯笼的时候,我看着就像中式恐怖片一样,可能小时候香港僵尸片看多了

还有最让我不解的是那边酒席最后才上筷子。。

如果你们也吃腻了外卖,或者也像我一样,在不知道下一步该怎么走的烂摊子里觉得心烦,可以尝尝这米。胜利村的,我老丈人自己种的。

没加什么科技与狠活,就是实实在在的五常稻花香 2 号大米。虽然我现在是个被 AI 干碎的失业前端,但自从吃了这五常大米,回不了头了,不知为啥这么香和有弹性。

岳父自己做的包装,好几款,有印了自己的照片当包装。具体分几种

编织袋(无真空) 7.8 元/斤

右边是编织袋,左边是礼盒装

塑封装(真空) 8.8 元/斤



礼品盒(真空) 9.8 元/斤


想尝尝的可以加我绿色泡泡,真名还是挡一下

“Claude 正在自掘坟墓。它自认为是 AI 公司中的苹果。”

 

“Claude AI,你们无缘无故封掉了我们整个组织,涉及 60 多个属于正规公司的账号,却没有给出任何解释。申诉这件事居然只能通过填写一个 Google 表单来处理?这用户体验和客户服务也太差了。”

 

Belo App CTO Pato Molina 发贴控诉,并配上了 Claude 回复的邮件。

报道显示,Belo 当前在拉丁美洲的用户数已超过 300 万,2025 年平台交易量超过 10 亿美元。

 

Molina 表示,“Anthropic 以涉嫌违反其使用条款为由,决定关闭我们整个组织的账号。至于我们具体违反了哪一条政策,我完全不清楚:我们只是收到一封邮件,然后就结束了,Claude 账号 直接被封。如果想申诉,居然还得去填一个 Google 表单,听起来就很离谱。”

 

“60 多人一下子失去了完成工作的核心工具。各种集成、skill、对话历史,要么全部丢失,要么被无限期冻结。这对任何在关键业务流程中依赖 AI 工具的软件公司来说,都是一个巨大的教训:永远不要把所有鸡蛋放在一个篮子里。”

 

“除了糟糕的用户体验和完全没有解释之外,这种做法其实是在直接伤害 Anthropic 自己的营收。他们刚刚封禁了一整家正规公司,涉及 60 多个付费账号,全部都在订阅和使用 API。这些都是真实客户带来的持续性收入,而且原本还在活跃使用中。”有网友说道。

 

动不动封号,用户长期投诉无门

.

Belo 公司成员们的遭遇并非个例。

 

Molina 的帖子下就有人表示,“我公司也遇到了同样的问题。没有任何预警,也没有任何解释。我们已经两次丢失了所有客户信息。这太荒谬了。”

 

还有开发者在三天前刚注册不久就被无缘无故封号了:

 

“我毫无理由就被封号了。我的账号在注册后 15 分钟内就被封了。当时我甚至还没发过一条提示词,也没有进行过任何 API 调用。我只是刚在本地搭建开发环境(VS Code、Node.js、CLI),封禁就发生了。

 

我怀疑问题出在一张公司共用的信用卡上。我的商业合伙人已经在他自己的 Claude 账号里绑定了这张卡,系统很可能把这种情况识别成了重复账户,从而触发了自动封禁。

 

我已经提交了多次申诉。第一次申诉被拒,但没有给出任何具体原因;后面的申诉则完全没有回应。每次给客服发邮件,都会收到自动回复,把我再次引导回申诉表单。整个过程就是一个让人非常沮丧的循环,从头到尾都没有任何真人来审核我的情况。

 

有没有人有办法真的让 Anthropic 的真人支持人员来查看案例?任何建议都非常感谢。

 

而在 IT 行业工作、今年 26 岁(1999 年出生)的开发者“Trummler12”,也莫名被封号了。这件事发生在 Anthropic 发布身份验证公告之前。

 

“我承认我有时候确实会有点幼稚,但是……我真的很好奇,这个判定算法到底是怎么做的,以及我和 Claude 的哪些互动竟会让它怀疑是未成年人在使用,是因为我母语不是英语?还是和我的一些情况有关(自闭症、ADHD)?”

 

被封当晚,Trummler12 提交了两次解封申诉:第一次稍微带点玩笑,第二次则认真说明自己是个开发者,很希望继续使用 Claude Code 来查找 Bug,以及处理一些非 vibe coding 的任务。但两天过去了,依然没有任何回复。

 

“我甚至还让他们扫描了我的脸,说实话我当时戴着墨镜(因为畏光),但应该很明显能证明我已经不是小孩了吧。”但依然没有通过。“我把胡子稍微留回来一点之后,年龄验证终于通过了(而且我还是戴着墨镜 😅)。”Trummler12 说道。

 

Trummler12 表示,经历了那次 Discord 年龄验证数据泄露事件之后,自己绝对不可能再把身份证发给任何平台。“说真的,年龄验证这件事本身在各个层面都很糟糕:隐私和安全风险高得离谱、技术上不准确,还带偏见、会制造一种虚假的安全感,真正的违法者总有绕过方法,还给滥用(广告、政治用途)打开了窗口。”

 

更早的八个月之前,遇到类似问题的企业版用户Monotonea求助官方客服无望,之后不得已发贴求助。

 

我说服公司购买了 Claude Team 的付费团队版,因为我相信这个 AI 服务可以成为同事们很好的学习工具。我们一共创建了 5 个团队账号,但令人震惊的是,其中有 2 位同事在刚创建账号后就立刻被封禁了。

 

这件事就发生在整个团队一起进行 onboarding 的现场。当时真的非常尴尬、非常挫败,我也对同事和公司都感到很愧疚,毕竟是我推动了这项尝试。

 

更糟的是,公司电话系统不支持短信,所以我还不得不让同事用各自的个人手机号来做验证。结果即便这样,他们还是马上被封了。我们第一时间联系了客服支持,但现在已经过去 4 天了,完全没有任何回复。

 

有没有人遇到过类似的情况?你们是怎么把账号解封的?有没有什么有效的方法可以把问题升级反馈给 Anthropic / Claude 的支持团队?任何建议或帮助我都会非常感激。谢谢大家。

 

Monotonea 强调,其用的邮箱都是有公司域名的官方邮箱,公司完全合法合规,公司及所有用户均位于 Claude 支持的国家/地区。“账户创建后立即被封禁,这让我感到非常奇怪和不安。我们通常通过公司 VPN 访问互联网,所以这可能是系统误判为可疑活动。但无论如何,我对客服缺乏响应速度和专业精神感到非常失望。”

 

“他们最近一个月左右肯定做了一些改动,导致自动封号的次数大幅增加。”从社交平台评论和 Reddit 上的帖子来看,这个问题越来越严重。有开发者指出,最糟糕的是,没有任何申诉途径,也得不到任何支持。”申诉流程简直是个笑话,就是一个谷歌表单,(看起来)完全没有人工干预。”

 

随着人们对 Anthropic 的不满情绪不断累积,近日,一个名为 Banned by Anthropic 的网站也上线了。

 

该网站以“推动人工复核与公平申诉机制”为核心诉求,集中收集并展示用户在使用 Claude 过程中遭遇账号封禁的案例,并呼吁 Anthropic 改进其封禁与申诉流程。

 

作为一个“公开事件记录与请愿平台”,该平台主要记录用户因自动化风控系统被封禁账号的经历,包括团队账号被封、订阅中断、项目受影响等问题。同时,网站强调目前申诉流程过于依赖表单提交,缺乏透明解释与及时反馈,用户在遭遇封禁后往往难以及时恢复服务。

 

网站发起方认为,随着 Claude 在企业与开发者场景中的使用不断增加,账号封禁已不再是单一用户问题,而可能对团队协作和业务连续性产生直接影响。因此,其提出的核心诉求包括:引入人工复核机制、提升申诉通道响应效率,以及提供更清晰的封禁原因说明。

 

“以我自身的经验来看,他们的安全保护措施确实有些过头了。每当我纯粹出于好奇,想学习对微生物学时,Opus 就会阻止我,并告诉我出于安全考虑应该使用 Sonnet。”有用户表示。

 

“单一厂商锁定”问题反复重现

 

Claude 封号潮中,另一个引发关注的话题就是“单一厂商锁定”。

 

这并不是一个新问题。云计算时代,企业就已经反复讨论过:一旦把关键基础设施、业务流程和历史数据都押在某一平台身上,一旦平台出问题,风险就会被无限放大。到了大模型时代,这个问题依然存在,甚至影响更加深入组织内部。

 

现在,AI 工具并不只是一个“聊天窗口”,它们正在嵌入公司的日常工作流,比如代码开发、内部知识库、客服系统、自动化流程等。一旦某个 AI 平台突然断供、封号,失去的可能是一整套正在运行的组织能力。

 

创业者 Ossy Nebolisa 就表示,“在互联网时代,平台封禁已成为最严重的商业风险之一。然而,大众对此却鲜有讨论。”

 

“让公司依赖单一供应商本身就是个糟糕的决策。我所有产品在编排器和大模型层面都做了幂等设计,就是为了避免这种依赖。作为股东,如果这位 CEO 连基本的应急预案都没有,我会尽快把他换掉。现在很多没有真正商业经验的人也能当上 CEO。”有网友表示。

 

是否要把 AI 基础设施押在一家公司身上?Molina 分析道,在公司内部同时使用多个 AI 平台,有利也有弊。

 

最大的优势是,在出现服务中断时可以保证业务连续性,就像我们现在在 Claude 上遇到的情况。就我们而言,我们也在使用 Gemini,但切换过去意味着要放弃已有的对话历史和集成流程。这不算致命问题,但确实需要时间来适应这种变化。

 

最大的劣势则是运营复杂度的提升。你需要让团队熟悉每一个平台,这会消耗时间和成本。此外,不同 AI 平台之间的集成也并不简单,后续维护会变得更加繁琐。

 

在实际中,很多公司最终会“绑定”某些服务稳定、口碑较好的供应商(比如 Slack、Gmail、Notion 等)。但无论如何,不能接受的是,一个服务在没有任何提前通知、也无法联系到客服支持的情况下突然下线。

 

“问题在于,这家公司和 OpenAI 一样,本质上是一种‘风口产物’。它们依靠炒作制造出来的需求而繁荣,然后制定一套过度且不切实际的限制性‘政策’,这些政策并没有建立在合理判断之上。当它们开始执行这些政策,而你提出不满时……”Tyreese Learmond 认为。

 

显然,Anthropic 正在以一家基础设施公司的姿态进入企业工作流,却没有拿出与之匹配的基础设施责任感。这不是 Anthropic 一家的问题,而是所有想要成为基础设施公司都需要思考和承担的责任。

 

正如一位网友的发问:

 

“我们还要眼睁睁看这种事发生多少次?每一个大众曾经热爱的全新平台,最终都会走到这一步:人们在上面建立维持生计的项目,然后某一天,一切突然消失,永久封禁,没有申诉渠道,没有人工介入,没有任何解释。只剩下一份 Google 表单,和一片死寂。”

 

参考链接:

https://x.com/patomolina/status/2045254152377323970

https://www.reddit.com/r/Anthropic/comments/1smfey3/on_april_13_2_days_ago_26yearold_me_got_banned/

https://www.reddit.com/r/ClaudeAI/comments/1n3sspf/paid_for_claude_team_plan_but_2_out_of_5_members/

CLI = Command-Line Interface中文叫:命令行界面 / 命令行工具

简单说:不用鼠标点图形界面,直接用键盘输命令、让电脑干活的方式,就叫 CLI。

    • *

举个最直观的例子

  • 你平时点图标、点按钮 → 这是 GUI(图形界面)
  • 你打开终端 / 黑框框,输命令执行 → 这就是 CLI

比如之前说的 SSL 证书:

bash

运行

certbot --nginx

这行就是在 CLI 里运行

    • *

你会遇到的常见 CLI 工具

  • Windows:CMD、PowerShell
  • Mac / Linux:终端(Terminal)
  • 宝塔、服务器面板里的:SSH 命令行
    • *

和你有什么关系?

你之前问 SSL 证书,里面提到的:

  • certbot
  • apt install
  • 各种配置 Nginx、Apache

这些全都是 CLI 操作

一句话总结:CLI = 用命令打字操作电脑 / 服务器,代替鼠标点来点去。

1. 注册英伟达 NIM ,这步就不详细说了,网上都有教程。
2. 打开 cc-switch ,添加供应商找到 Nvidia



3. 请求地址不需要变,填上 API key ,注意 API 格式为:OpenAI Chat Completions



4. 填写模型,注意要写完整模型供应商/模型名,不知道怎么写的可以直接点击右上角获取模型列表



5. 配置完模型后打开设置,找到代理,打开这两个选项



6. 配置完这些后直接启动 claude code 就可以使用了,不过是真的慢。

目前在 Claude code Cli 下使用没有问题,但是在 VS Code 的插件中使用会报错,插件中对话中断,实际还在运行



猜测是消息格式的问题

这是一个悲伤的实盘复盘,也是一篇价值可能远超本金的“避坑指南”。

Img
Img
交学费了

背景:2005 年就开了股票账户,但一直没有买卖过股票,觉得看不懂。直到 2025 年初,才开始学习研究量化,并用 2.5 万起步人工或量化实盘。

比较典型新手行为:2025 年 6 月 24 日 2.5 万开始,跑了 1 周效果不错,7 月 1 日加仓到 5 万,又看这不错,8 月 12 日加仓到 10 万,经过 9 月,10 月,11 月收益震荡下行,hold 不住了,12 月中旬逐步减到 3 万,被市场上了一课,交了充足的学费。

截止今天亏损 19538 元,亏损比例-20.75%,实际量化亏损没这么多,量化亏损 11359 元,亏损比例-10.17%,其他 8000 多元是人工操作亏的(新手常见行为:看不得资金空仓,有资金就想操作,量化空仓就人工操作)。

我分别记录了我每个实盘量化策略的交割单,一看就知道各个量化策略的亏损情况。

前后总共实盘过 5 个策略,现在还在实盘的策略 2 个,另外 3 个停掉了,5 个策略都是小市值策略。

Img
因为作为一个菜鸟,深知股市水深,所以入场前我给自己定了个死规矩:只拿“全亏完也不会影响明天中午吃猪脚饭”的钱来试水。

这一年,从刚跑通第一个策略时坚信能“打造印钞机”,到后来被市场反复毒打、在深夜里改 Bug ,我经历了一个典型“量化韭菜”的完整心路历程。今天,我们就来算算这笔账。


1. 初入量化的“上帝视角”(过度自信期)

每个刚碰量化的人,都会经历一段短暂的“蜜月期”。

那时候,只要在回测平台上稍微调整几个参数(比如把均线周期改一改,加个 MACD 过滤),就能跑出一条令人血脉贲张的“完美 45 度角”向上收益曲线。

Img
看到的让人心动的策略收益示例

带着“原来搞钱这么容易”的错觉,我把这 2 万块真金白银接入了实盘。
第一天上线的时候,那种看着程序自动读取行情、自动下单、自动撤单的爽感,让我有一种稳拿诺贝尔经济学奖的错觉。

然后,现实的毒打立刻就来了。
我遇到的第一个大坑,不是策略失效,而是代码 Bug 。
比如,策略条件触发了,但因为没有处理好“涨跌停板买不进/卖不出”的逻辑,程序疯狂向交易所发废单报报错;或者因为网络抖动了一下,持仓状态没对齐,该卖的没卖,导致直接吃了隔夜的一个大跌。

那一刻我才明白:“写一个能在历史数据里赚钱的策略”和“写一套能在现实世界里活下来的交易系统”,完全是两码事。


2. 市场的毒打与信仰崩塌(绝望之谷)

度过了最初的工程摩擦期,真正考验心脏的是极端的市场行情。

回测里的数字是冰冷的,回撤 20%在你眼里可能只是 Excel 里的一个“-0.2”。但在实盘里,看着账户每天缩水,你的心理防线是会崩溃的。

今年遇到了好几波风格剧变(比如微盘股的流动性危机)。我眼睁睁看着往日表现优异的策略连续吃面。

Img
实盘大回撤瞬间*

在这种压力下,我犯了量化交易的大忌——人工干预机器。
看着连续下跌,我实在忍不住了,心想“这肯定不对劲”,于是强行手动平仓,甚至直接停掉了策略。结果往往是:我刚一平仓,第二天就大涨反弹;等我懊悔地再把程序开起来,它又接到了山顶上。

机器的逻辑被我的人性彻底破坏,两头挨耳光。

到了现在算总账,这 2 万块钱最终……(亏损 19538 元,亏损比例-20.75%)。讲真,我还不如把它放在余额宝里赚顿排骨汤。


3. 亏钱买来的 4 个“血泪教训”

虽然亏了钱,但这 2 万块的学费交得值。我总结了 4 个极其昂贵的教训:

教训一:千万警惕“过拟合”与未来函数

你以为你发现的圣杯,往往只是你的模型恰好“背诵”了过去的历史答案。市场是动态博弈的,过去有效不代表未来有效。如果在回测里加了太多条件去过滤亏损交易,实盘必然扑街。

? 避坑参考资料:如果你不确定自己的策略是否陷入了“过拟合”的陷阱,建议跑实盘前先看看这篇聚宽社区大佬的干货:策略过拟合诊断工具,里面提供了一套非常系统性的实战自我诊断方法。

教训二:磨损是看不见的“利润刺客”

很多新手回测时根本不设滑点,或者把手续费设得极低。在小资金加上稍高频的交易下,买卖一次的印花税、佣金,加上实盘买高一分、卖低一分的滑点,能把你预期的微薄利润吃得干干净净。你以为你在赚钱,其实你在给券商打工。

我实际量化实盘用的是一个免 5 低佣账号,手续费已经是很低很低了,不然亏损会更多。

Img
Img

教训三:稳定大于一切,工程能力决定下限

策略再好,API 挂了、断网了、订单没成交导致状态死锁了,全都没用。做好异常处理、断线重连、实盘与本地账户的数据对账,这些枯燥的“基础设施”建设,花的时间比写策略本身还要多。

教训四:量化交易,其实更考验“人性”

最大的敌人不是市场,而是那个看着账户回撤想要“拔网线”的自己。真正成熟的量化交易,是要在这个系统跑之前就想清楚所有极端情况,然后闭上眼睛,让机器执行。


4. 总结与下一步:我还做量化吗?

做,当然继续做。

虽然第一年交了学费,但量化帮我戒掉了作为一个散户的“赌徒心理”。我不再凭感觉冲动买卖,不再去听信各种大 V 的小道消息,之前加的几个大 V 的股票群也退了。它强迫我建立起了一套客观、去情绪化、可验证的市场分析框架。

接下来的计划,我会回归常识,降低对收益的虚幻预期,把精力更多地放在交易系统的底层建设上。之前觉得策略回测年化没个几十个点,都不好意思发出来,也不会考虑去实盘,现在觉得能稳定跑赢指数,控制回撤,就是不错的策略了。

更关注策略的实盘表现,而不是回测表现。也希望从技术的角度,在策略实盘前也能尽可能的通过工具评估策略可能的风险(比如上上面提到的社区的过拟合诊断工具),而不是盲目上实盘。也认识到不同策略有不同的适用市场,需要根据市场情况选择合适的策略。

Img
Img

最近在研究的策略

个人的力量和认知是有限的,向大家学习,精进自己,也希望和大家一起交流,共同进步,任重道远。

最后,给所有想用 Python 写个代码或量化平台复制一个策略就去股市里捡钱的新手一句忠告:永远敬畏市场!请务必只拿“亏光了也不影响生活”的钱来交学费。

题主现有工作内容是对消费者调研数据进行分析和洞察,spss code 编写,基本是初级分析和跑数工具人的角色。

公司也是在大搞 Ai 提效和裁员,要求年内搞一个 Ai 工具/Agent 出来,把自己的工作流程和内容打包,上传到内网的平台上,这样其他同事可以直接使用这个 Agent 连接数据库跑数和分析,美名其曰提效减少我的工作量,实际大家心里都清楚,减少的工作量并不会让我闲着,而是会给我安排更多其他的工作,同时也可以替代我现有的工作内容。

对于这件事我很反感,Ai 本应让我提效有更多时间做自己的事,而不是让我为公司做更多的事(且没有任何奖励)和替代我,所以我并不想去推进这件事,但是又没办法拒绝,因为这个需求是公司层面向直属上司要求的,然后他安排给了我,我和直属上司的关系并不差,不想撕破脸翻脸,所以只能强吃这口屎。

目前在这家公司八年,去年空降了新的大领导以后我们并入了其他团队,我个人希望尽快被裁拿钱走人,公司是想逼我搞 Ai 替代我然后不给裁员费让我自己走人,应该要如何把这件事推进的看起来很顺利但最后烂尾让公司赶我走呢。

最近行情很好,成交量屡创新高。楼上邻居正好在卖,年初无人问津,上个周末来看的人巨多。相比年初的挂牌价,现在已经涨了 10%,依然挡不住大家的热情。纵观全市行情,也普遍止跌回升了,趁着现在还在低点,可以入手吗?老破小的租售比还可以,能到年化 4%~5%