thinking模式深度推理:M3怎么帮你修最难的Bug
M3提供thinking和non-thinking双模式。thinking模式让模型"先想后答",在复杂Bug修复场景下效果显著。本文用3个真实案例展示thinking模式的威力。
thinking vs non-thinking
| 模式 | 思考过程 | 延迟 | 适用场景 |
|---|---|---|---|
| thinking | 有(类似CoT) | 10-30s | Bug修复、架构设计、复杂推理 |
| non-thinking | 无 | <2s | 代码补全、格式化、简单问答 |
| auto | 自动判断 | 自适应 | 日常开发 |
# monkeycode.yaml
model:
provider: minimax
model: m3
m3:
mode: thinking # 强制thinking
# mode: non-thinking # 强制non-thinking
# mode: auto # 自动选择
案例1:并发数据竞争Bug
Bug描述
# 一个"看起来没问题"的代码,但在高并发下会出现数据竞争
class OrderProcessor:
def __init__(self):
self.pending_orders = []
async def process_payment(self, order_id: str):
# 1. 检查是否已在处理
if order_id in self.pending_orders:
return {"status": "already_processing"}
# 2. 加入待处理列表
self.pending_orders.append(order_id)
# 3. 处理支付
result = await payment_gateway.charge(order_id)
# 4. 从列表移除
self.pending_orders.remove(order_id)
return result
non-thinking模式的输出
# non-thinking: 快速给出了一个表面修复
class OrderProcessor:
def __init__(self):
self.pending_orders = set() # 改成set,O(1)查找
async def process_payment(self, order_id: str):
if order_id in self.pending_orders:
return {"status": "already_processing"}
self.pending_orders.add(order_id)
result = await payment_gateway.charge(order_id)
self.pending_orders.discard(order_id)
return result
# ⚠️ 没有解决并发问题!两个协程可能同时通过检查
thinking模式的输出
# thinking: 先分析了并发问题的根因,再给出正确方案
"""
思考过程:
1. 问题:asyncio中await会释放控制权,两个协程可能在步骤1和步骤2之间切换
2. set()替换list()只优化了查找性能,不解决并发安全问题
3. asyncio本身是单线程的,但await点会导致协程切换
4. 需要用asyncio.Lock保护临界区
5. 还要考虑异常情况:如果charge()抛异常,order_id不会被移除
"""
import asyncio
class OrderProcessor:
def __init__(self):
self.pending_orders = set()
self._lock = asyncio.Lock() # 临界区锁
async def process_payment(self, order_id: str):
async with self._lock: # 原子操作:检查+添加
if order_id in self.pending_orders:
return {"status": "already_processing"}
self.pending_orders.add(order_id)
try:
result = await payment_gateway.charge(order_id)
return result
finally:
async with self._lock: # 原子移除
self.pending_orders.discard(order_id)
差异:thinking模式找到了根因(asyncio的协程切换),并给出了异常安全方案。
案例2:SQLAlchemy N+1查询
Bug描述
# 一个简单的API,返回所有用户及其文章列表
@router.get("/users")
async def list_users():
users = await db.execute(select(User))
return [{"id": u.id, "name": u.name, "posts": [{"title": p.title} for p in u.posts]} for u in users]
thinking模式的思考过程
1. 识别问题:u.posts触发了lazy loading,N+1查询
2. 分析原因:SQLAlchemy默认lazy loading,每次访问relationship都发一次SQL
3. 考虑方案:
- selectinload:2次查询(1次用户+1次所有文章)
- subqueryload:2次查询(子查询方式)
- joinedload:1次查询(JOIN方式)
4. 选择selectinload:避免JOIN导致的重复数据
5. 额外优化:只查询需要的列,减少数据传输
# thinking模式输出
from sqlalchemy.orm import selectinload
@router.get("/users")
async def list_users():
result = await db.execute(
select(User)
.options(selectinload(User.posts)) # 批量加载文章
.order_by(User.id)
)
users = result.scalars().all()
return [
{
"id": u.id,
"name": u.name,
"posts": [{"title": p.title} for p in u.posts]
}
for u in users
]
# 查询次数从N+1降低到2,性能提升10-100倍
案例3:内存泄漏
Bug描述
一个FastAPI服务运行几天后内存持续增长,最终OOM。
thinking模式的推理链
1. 先分析常见的Python内存泄漏原因:
- 全局缓存无限增长
- 事件循环引用
- 数据库连接未关闭
- asyncio Task未清理
2. 审查代码发现:
- lru_cache装饰器没有设maxsize
- 使用了全局dict作为缓存,没有过期策略
3. 根因:@lru_cache(None) + 无限增长的缓存dict
# thinking模式输出
# 修复1:限制lru_cache大小
from functools import lru_cache
@lru_cache(maxsize=1024) # 设置上限
def get_user_permissions(user_id: int):
...
# 修复2:缓存增加TTL
from cachetools import TTLCache
# 最大1000条,每条5分钟过期
api_cache = TTLCache(maxsize=1000, ttl=300)
# 修复3:数据库连接确保关闭
from contextlib import asynccontextmanager
@asynccontextmanager
async def get_db_session():
session = Session()
try:
yield session
finally:
session.close()
什么时候用thinking模式?
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 代码补全 | non-thinking | 简单快速 |
| Bug修复 | thinking | 需要推理根因 |
| 架构设计 | thinking | 需要多方案对比 |
| 代码审查 | thinking | 需要理解上下文 |
| 写单元测试 | non-thinking | 模板化 |
| 性能优化 | thinking | 需要深入分析 |
总结
thinking模式的核心价值是先诊断再开药方:
- 并发Bug:non-thinking只改表面,thinking找到根因
- N+1查询:thinking给出完整的优化链路
- 内存泄漏:thinking系统化排查多个可能原因
MonkeyCode默认auto模式,复杂任务自动切换thinking,日常编码用non-thinking保持低延迟。

浙公网安备 33010602011771号