Python实现扑克AI代理:不完全信息博弈与深度强化学习实战
简介这是一份面向人工智能与强化学习学习者的德州扑克 AI 代理实现项目源自斯坦福大学 CS 221 课程最终项目。项目将扑克博弈建模为马尔可夫决策过程结合 Q-Learning、蒙特卡罗模拟与 epsilon-greedy 策略训练智能体先与紧攻击型、松散攻击型、紧被动型、松散被动型及随机对手对战学习再实现自我对弈或与人类玩家对战适合想深入理解 MDP 与强化学习落地的中高级开发者参考。资源包共 8 个文件约 26KB以 Python 源码为主包含 3 个 py 脚本、2 个 pyc 编译文件以及 1 个 md 说明文档和 gitignore、gitattributes 等工程配置文件结构紧凑、便于直接运行与二次修改。目前已有 1551 人学习下载。通过阅读源码读者可掌握状态抽象、动作空间设计、奖励函数设定与 Q 表更新等关键环节并借鉴蒙特卡罗模拟在不确定信息博弈中的采样思路为自身强化学习项目提供可复用的实现范式与排错参考。1. 从零拆解一个扑克 AI 代理Python 实现里到底藏着什么很多人第一次听到“扑克 AI 代理”脑子里浮现的是赌场里那种能算牌的机器或者某个能横扫牌桌的玄学模型。但真正拆开来看它其实是一个典型的不完全信息博弈问题你看不到对手的底牌对手也看不到你的双方只能通过下注动作来推断彼此的范围。这和象棋、围棋那种双方信息完全透明的游戏有本质区别——后者可以用搜索树暴力推演前者不行你必须建模“对手在想什么”。这份资源给出的是一套用 Python 实现的扑克 AI 代理核心思路是围绕状态表示、动作空间、策略网络和对手建模四个模块展开。它适合两类人一类是想学博弈论与强化学习结合落地的开发者另一类是想拿一个完整可跑的项目来理解“不完全信息下怎么做决策”的工程师。你不需要先成为德扑高手但得能看懂 Python 类结构和基本的概率计算。下面我从代码结构一路拆到参数调优把能复现的细节都摆出来。2. 拆开代理的骨架状态编码、动作空间与决策循环2.1 状态编码把牌桌信息压成网络能吃的张量扑克 AI 的第一个难点不是模型多大而是怎么把一手牌、公共牌、筹码、位置、历史动作这些异构信息塞进一个固定维度的向量。常见做法是分通道编码手牌用 52 维的 one-hot 表示公共牌同理筹码和底池做归一化位置和动作历史用 embedding 或者直接拼 one-hot。我一般会按下面这个结构来组织状态编码器代码不复杂但每个维度的含义必须写清楚不然后面调参就是黑匣子。import numpy as np class StateEncoder: 把一局牌的状态编码成固定长度向量 def __init__(self): self.card_dim 52 # 一副牌 52 张one-hot self.action_dim 10 # 动作历史窗口最近 10 步 self.scalar_dim 6 # 底池、己方筹码、对手筹码、位置、轮次、有效下注 def encode(self, hole_cards, community_cards, pot, my_stack, opp_stack, position, street, last_actions): # 手牌 one-hot两张牌置 1 hole np.zeros(self.card_dim, dtypenp.float32) for c in hole_cards: hole[self._card_index(c)] 1.0 # 公共牌 one-hot翻牌 3 张、转牌 1 张、河牌 1 张 board np.zeros(self.card_dim, dtypenp.float32) for c in community_cards: board[self._card_index(c)] 1.0 # 标量归一化底池和筹码除以初始筹码位置和轮次除以最大值 scalars np.array([ pot / 200.0, my_stack / 200.0, opp_stack / 200.0, position / 6.0, street / 3.0, last_actions[-1] / 5.0 if last_actions else 0.0 ], dtypenp.float32) # 动作历史取最近 10 步不足补零 hist np.zeros(self.action_dim, dtypenp.float32) for i, a in enumerate(last_actions[-self.action_dim:]): hist[i] a / 5.0 return np.concatenate([hole, board, scalars, hist]) def _card_index(self, card): # card 格式如 As、Kh转成 0-51 rank_map {r: i for i, r in enumerate(23456789TJQKA)} suit_map {s: i for i, s in enumerate(shdc)} return rank_map[card[0]] * 4 suit_map[card[1]]这段代码里最容易被忽略的是归一化。底池和筹码如果不除以初始筹码数值可能到几千而 one-hot 只有 0/1两者拼在一起送进网络梯度会被大数值主导训练时 loss 震荡得厉害。另一个坑是动作历史的窗口长度设 10 是经验值太短记不住对手的加注节奏太长则稀疏且增加输入维度。位置编码用 0 到 6 表示枪口到按钮这个顺序不能乱否则模型学到的位置优势和实际相反。2.2 动作空间为什么不是简单的“跟注或加注”扑克的动作空间看起来只有弃牌、跟注、加注三种但加注的尺度是连续的。如果直接把加注金额作为连续动作输出策略网络很难收敛因为不同底池下的合理加注范围差异巨大。常见做法是离散化把加注分成底池的 0.5 倍、0.75 倍、1 倍、1.5 倍、2 倍再加上全下一共 6 档加上弃牌和跟注总共 8 个离散动作。class ActionSpace: 离散化加注尺度输出 8 个动作 def __init__(self, pot_fractions(0.5, 0.75, 1.0, 1.5, 2.0)): self.fractions pot_fractions self.num_actions 2 len(pot_fractions) 1 # 弃牌、跟注、5 档加注、全下 def get_legal_actions(self, pot, my_stack, to_call): 返回当前合法动作的掩码和对应金额 actions [] # 0: 弃牌 actions.append((fold, 0)) # 1: 跟注 call_amount min(to_call, my_stack) actions.append((call, call_amount)) # 2-6: 按底池比例加注 for f in self.fractions: raise_amount int(pot * f) total to_call raise_amount if total my_stack: actions.append((raise, total)) else: actions.append((allin, my_stack)) # 7: 全下 actions.append((allin, my_stack)) return actions def action_mask(self, legal_actions): 生成掩码非法动作为 0 mask np.zeros(self.num_actions, dtypenp.float32) for i, (name, amount) in enumerate(legal_actions): if i self.num_actions: mask[i] 1.0 return mask这里的关键参数是pot_fractions。我试过只留 0.5 和 1.0 两档模型学出来的策略非常死板翻牌前只会迷你加注容易被对手读死。加到 5 档之后策略明显丰富但训练时间也上去了。另一个细节是全下动作要单独处理当加注金额超过剩余筹码时必须截断成全下否则会出现筹码为负的非法状态。动作掩码在推理时一定要用不然模型可能输出一个筹码不够的加注直接翻车。2.3 决策循环从发牌到动作输出的完整链路把状态编码和动作空间串起来就是一个完整的决策循环。下面这段是代理的主循环每到一个决策点就调用一次。class PokerAgent: def __init__(self, model, encoder, action_space): self.model model self.encoder encoder self.action_space action_space def act(self, game_state): # 1. 编码状态 state_vec self.encoder.encode( game_state[hole_cards], game_state[community_cards], game_state[pot], game_state[my_stack], game_state[opp_stack], game_state[position], game_state[street], game_state[action_history] ) # 2. 获取合法动作 legal self.action_space.get_legal_actions( game_state[pot], game_state[my_stack], game_state[to_call] ) mask self.action_space.action_mask(legal) # 3. 模型前向输出动作概率 logits self.model.predict(state_vec[np.newaxis, :]) masked_logits logits (1 - mask) * (-1e9) # 非法动作置极大负值 probs softmax(masked_logits) # 4. 按概率采样或取 argmax action_idx np.random.choice(len(probs), pprobs) return legal[action_idx]逻辑说明第 1 步编码状态注意game_state里的字段名要和编码器参数一一对应少一个就会报 KeyError。第 2 步拿合法动作这一步不能省因为不同轮次、不同筹码深度下合法动作集合是变化的。第 3 步的掩码操作是推理阶段必须做的训练时可以在 loss 里加 mask但推理时如果忘了加模型可能输出一个弃牌以外的非法动作。第 4 步采样还是 argmax 取决于场景训练时用采样增加探索实战时用 argmax 保证稳定。我一般会在前 1000 手用采样之后切 argmax。3. 训练策略网络用 CFR 还是深度强化学习3.1 CFR 与深度 RL 的选型对比扑克 AI 的训练方法主要有两条路反事实遗憾最小化CFR和深度强化学习DQN/PPO。CFR 是博弈论里的经典方法理论上能收敛到纳什均衡但它的计算量随状态空间指数增长适合抽象后的有限状态。深度 RL 则用神经网络拟合价值函数能处理更大状态空间但训练不稳定容易过拟合到对手的特定策略。我一般会这样选如果目标是单挑无限注德州扑克且算力有限先用 CFR 做抽象把牌力分成若干桶再在抽象博弈上求解。如果目标是多桌、多对手且能拿到大量对局数据用深度 RL 更合适。这份资源里的实现是深度 RL 路线用 PPO 做策略优化因为它的动作空间是离散的PPO 的 clip 机制比 DQN 的 Q 值估计更稳。3.2 PPO 训练脚本与关键超参下面是一个简化的 PPO 训练循环重点看超参设置和优势估计。import torch import torch.nn as nn import torch.optim as optim class PolicyNet(nn.Module): def __init__(self, input_dim, hidden_dim, action_dim): super().__init__() self.fc nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, action_dim) ) def forward(self, x): return self.fc(x) def train_ppo(agent, env, epochs1000, batch_size256, clip_eps0.2, lr3e-4, gamma0.99, lam0.95): optimizer optim.Adam(agent.model.parameters(), lrlr) for epoch in range(epochs): states, actions, rewards, log_probs, values [], [], [], [], [] # 采样一批对局 for _ in range(batch_size): traj env.rollout(agent) states.extend(traj[states]) actions.extend(traj[actions]) rewards.extend(traj[rewards]) log_probs.extend(traj[log_probs]) values.extend(traj[values]) # 计算 GAE 优势 advantages compute_gae(rewards, values, gamma, lam) returns advantages values # PPO 更新 for _ in range(4): # 每批数据重复利用 4 次 new_logits agent.model(torch.FloatTensor(states)) new_log_probs log_softmax(new_logits, actions) ratio torch.exp(new_log_probs - torch.FloatTensor(log_probs)) surr1 ratio * torch.FloatTensor(advantages) surr2 torch.clamp(ratio, 1 - clip_eps, 1 clip_eps) * torch.FloatTensor(advantages) policy_loss -torch.min(surr1, surr2).mean() value_loss nn.MSELoss()(agent.model(torch.FloatTensor(states)), torch.FloatTensor(returns)) loss policy_loss 0.5 * value_loss optimizer.zero_grad() loss.backward() optimizer.step()参数说明clip_eps0.2是 PPO 的默认值控制新旧策略的偏离程度调大到 0.3 会让更新更激进但容易崩调小到 0.1 则学习慢。gamma0.99是折扣因子扑克一局通常几十步0.99 足够看到长期收益。lam0.95是 GAE 的平滑参数越高方差越大偏差越小。lr3e-4是 Adam 的常见起点如果 loss 震荡就降到 1e-4。batch_size256是每轮采样的对局数太小梯度噪声大太大则更新频率低。我一般会先跑 100 轮看 reward 曲线如果一直不涨先检查状态编码有没有归一化再检查动作掩码有没有漏。3.3 对手建模用历史动作估计范围纯策略网络只学自己的最优策略但扑克是对抗性的你必须根据对手的动作调整。常见做法是维护一个对手范围表根据对手在每个动作节点的频率反推他手里的牌力分布。比如对手在翻牌前加注他的范围可能是强牌加部分诈唬如果他在转牌继续下注范围进一步收窄。class OpponentModel: def __init__(self): self.range_table {} # 节点 - 手牌概率分布 def update(self, node, action, hand_strength): 根据对手动作更新范围 if node not in self.range_table: self.range_table[node] np.ones(1326) / 1326 # 1326 种起手牌组合 # 贝叶斯更新动作概率乘以先验 likelihood self._action_likelihood(action, hand_strength) self.range_table[node] * likelihood self.range_table[node] / self.range_table[node].sum() def _action_likelihood(self, action, strength): # 强牌更可能加注弱牌更可能弃牌 if action raise: return 0.8 if strength 0.7 else 0.2 elif action call: return 0.5 else: return 0.1 if strength 0.7 else 0.9这个模型的精度取决于_action_likelihood的设计。我一般会先用一个粗略的阈值跑起来然后根据实际对局数据做校准。注意范围表的大小是 1326对应 52 张牌里选 2 张的组合数不要写成 52×51那样会重复计算。4. 避坑与排查训练不收敛、动作非法、胜率虚高4.1 现象loss 震荡不下降reward 长期为负原因最常见的是状态编码里混入了未归一化的大数值比如底池直接用了原始筹码数而 one-hot 是 0/1两者量级差几百倍网络梯度被大数值主导。另一个原因是动作掩码在训练时没加模型输出了非法动作环境返回负奖励策略被带偏。解决把所有连续变量除以一个固定基准初始筹码或最大底池确保输入向量每个维度都在 0 到 1 附近。训练时在 loss 里加动作掩码非法动作的 logit 置 -1e9。跑之前先打印一批状态向量看有没有超过 10 的数值。4.2 现象推理时输出“加注 300”但筹码只有 200原因动作空间离散化时加注金额是按底池比例算的但没和剩余筹码比较。当底池很大、筹码很少时算出来的加注额会超过筹码。解决在get_legal_actions里加判断如果total my_stack就把动作改成全下金额设为my_stack。同时动作掩码要对应更新确保全下动作合法。4.3 现象训练胜率 70%实战一局就输原因过拟合到训练对手的特定策略。训练时对手可能是固定风格的脚本模型学会了针对它的打法但实战对手风格不同策略失效。解决训练时用对手池每轮随机从多个不同风格的脚本里选一个作为对手包括紧凶、松凶、跟注站、诈唬狂。对手池越大策略泛化越好。我一般会准备 5 到 10 个脚本对手每 100 轮换一次。4.4 现象CFR 抽象后策略和实际牌力脱节原因牌力分桶太粗比如把 AA 和 22 分到同一桶策略会把 22 当 AA 打。解决分桶时用手牌胜率而不是简单的高牌点数。常见做法是用蒙特卡洛模拟每种起手牌对随机手牌的胜率然后按胜率分位数分桶。桶数一般 10 到 20 个太少丢信息太多则抽象失去意义。4.5 现象训练到后期 reward 突然崩掉原因PPO 的 clip 参数太小或学习率太高策略更新步子太大直接跳出合理区域。也可能是优势估计的方差太大导致梯度方向错误。解决把clip_eps从 0.2 降到 0.1学习率从 3e-4 降到 1e-4同时增大 batch_size 到 512。如果还崩检查 GAE 的lam是不是设成了 1.0那样方差会很大改成 0.95。5. 进阶技巧用抽象加速训练与蒙特卡洛胜率验证5.1 牌力抽象把 1326 种组合压到 20 个桶深度 RL 直接处理 1326 种起手牌组合状态空间太大训练慢且容易过拟合。常见做法是先做牌力抽象用蒙特卡洛模拟每种组合对随机手牌的胜率然后按胜率分位数分成 20 个桶。这样输入维度从 1326 降到 20训练速度能快一个数量级。def build_abstraction(num_buckets20, samples10000): 用蒙特卡洛胜率做牌力分桶 combos list(itertools.combinations(range(52), 2)) win_rates [] for combo in combos: wins 0 for _ in range(samples): opp random.sample([c for c in range(52) if c not in combo], 2) board random.sample([c for c in range(52) if c not in combo and c not in opp], 5) if evaluate(combo board) evaluate(opp board): wins 1 win_rates.append(wins / samples) # 按胜率排序后等频分桶 sorted_idx np.argsort(win_rates) bucket_map {} for rank, idx in enumerate(sorted_idx): bucket_map[combos[idx]] rank * num_buckets // len(combos) return bucket_map参数说明samples10000是每种组合的模拟次数10000 次后胜率的标准误大约 0.5%足够分桶。num_buckets20是经验值我试过 10 个桶AA 和 KK 会分到一起策略区分度不够30 个桶则抽象收益递减训练时间反而增加。分桶后状态编码里的手牌 one-hot 改成桶的 one-hot维度从 52 降到 20。5.2 蒙特卡洛胜率验证别只看 reward 曲线训练时 reward 上涨不代表策略真的变强可能只是对手变弱了。我一般会每 500 轮做一次蒙特卡洛胜率验证让当前策略和一组固定基准策略比如随机策略、紧凶策略各打 1000 局统计胜率。如果对随机策略胜率低于 60%说明策略还没入门对紧凶策略胜率低于 45%说明对抗性不够。def evaluate_against_baseline(agent, baseline, num_hands1000): wins 0 for _ in range(num_hands): env PokerEnv(opponentbaseline) result env.play_hand(agent) if result 0: wins 1 return wins / num_hands # 每 500 轮调用一次 if epoch % 500 0: wr_random evaluate_against_baseline(agent, RandomPolicy()) wr_tight evaluate_against_baseline(agent, TightAggressivePolicy()) print(fEpoch {epoch}: vs Random {wr_random:.2%}, vs Tight {wr_tight:.2%})这个验证方法比看 reward 曲线靠谱得多因为 reward 受对手风格影响大而固定基准策略是稳定的。我一般会设三个基准随机、紧凶、松凶三个胜率都达标才算训练合格。从那以后我每次训练新模型都强制走一遍这个验证流程不再只看 loss 和 reward。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

九月开源项目盘点:开发效率、AI应用、数据处理与运维工具精选

九月开源项目盘点:开发效率、AI应用、数据处理与运维工具精选

1. 九月开源项目盘点的整体筛选思路1.1 为什么“月度盘点”这件事值得认真做每个月都有大量开源项目冒出来,但真正值得花时间研究的其实不多。我做月度盘点这件事已经持续了挺长时间,最大的体会是:筛选比收集重要得多。GitHub 上每天新增的仓…

2026/10/13 13:37:48 阅读更多 →
我用 Claude Code 做 Code Review 两个月,Bug 漏检率从 41% 降到 11%:TaoToken 统一 Key 接入实战

我用 Claude Code 做 Code Review 两个月,Bug 漏检率从 41% 降到 11%:TaoToken 统一 Key 接入实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 13:36:51 阅读更多 →
卫星云图识别CV大作业:从CSV到CNN全链路源码与避坑指南

卫星云图识别CV大作业:从CSV到CNN全链路源码与避坑指南

简介:一份面向计算机视觉课程的大作业解决方案,聚焦卫星云层图像的理解与识别。项目以Python为主要实现语言,附带实验报告PDF、答辩PPT和README说明,适合高校计科、人工智能、自动化等专业的学生用于课程设计、毕业设计或作为入门…

2026/10/13 13:36:58 阅读更多 →

最新新闻

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

简介:面向 YOLOv11 模型验证需求,这份精简版鸟类目标检测数据集包含一张真实野外鸟类图像及配套标准标注,可用于快速原型验证、轻量级部署测试与小样本检测基线建立。压缩包共五个文件,包含三张 JPG 图像、一个数据配置文件与一个…

2026/10/14 3:39:38 阅读更多 →
ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

简介:一套基于ASP.NET与SQL Server的葡萄酒网上商城销售系统,面向ASP.NET WebForm学习者、毕业设计学生以及需要搭建在线商城教学演示的开发者。系统围绕普通会员、商户会员和管理员三类角色展开,覆盖商品管理、购物车、订单处理、发货、商户…

2026/10/14 3:39:38 阅读更多 →
LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

简介:这是一份LangChain入门与实践的项目代码包,面向正在学习大模型应用开发的Python开发者,旨在帮助读者快速理解LangChain的模块化设计与核心用法。包内共3个文件,包含一个HTML格式的入门讲解页、一个项目运行配置文件以及一个版…

2026/10/14 3:39:38 阅读更多 →
C++学习日记 Day21:C++11(下)lambda表达式和function包装器

C++学习日记 Day21:C++11(下)lambda表达式和function包装器

## 今天学了什么今天学习C11的lambda表达式和function包装器。## 可调用对象概念:在C中有一类对象可像函数一样调用;分类:①函数指针using prt void(*)(int, string); prt f1 fun; f1(1, "函数指针");②仿函数 --有 operator&am…

2026/10/14 3:39:38 阅读更多 →
一人公司AI工作流:6步实现内容生产去体力化

一人公司AI工作流:6步实现内容生产去体力化

1. 一人公司的内容困局与破局思路一个人做内容,最怕的不是没灵感,而是灵感来了却卡在“执行”上。写一篇长文要三小时,做一张配图要半小时,剪一条短视频要一整个下午,排版发布又要来回切换四五个平台。一天下来&#x…

2026/10/14 3:39:38 阅读更多 →
8765平台前后摄DVDD电压不一致排查与修复指南

8765平台前后摄DVDD电压不一致排查与修复指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 3:38:38 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →