乐于分享
好东西不私藏

我用Claude生成API文档时,发现它把接口描述完全搞反了

我用Claude生成API文档时,发现它把接口描述完全搞反了

排查了半天才发现,问题根本不在代码


昨天搞了一个下午加晚上,差点没把我心态搞崩

事情是这样的,我们组有个内部的用户管理系统,是用FastAPI写的,之前做的时候比较赶,文档就随便写了写最近产品那边说要做二期功能,需要把现有的接口整理一下文档我一想,这不正好可以让AI帮忙吗,现在Claude这么火,让他帮我把接口代码转换成API文档,岂不是美滋滋

然后我就把整个项目丢给Claude,让它给我生成一份完整的API文档

结果文档是生成了,看起来像模像样的,我拿给产品经理看产品经理看了之后問了我一个问题:“这个登录接口,为什么返回的expires_in是负数token过期时间还能是负的吗

我当时就愣住了打开文档一看,好家伙,Claude在接口描述里写着:

expires_in: token的剩余有效时间,单位秒为正数时表示未过期,为负数时表示已过期

这他娘的什么鬼token过期时间还能为负数我从业这么多年就没见过负数的过期时间

我第一反应是:完了,代码写错了


开始排查:我以为是我的代码有问题

我赶快回去看代码我们登录接口是这样写的:

@router.post("/login")asyncdeflogin(request: LoginRequest):# 生成token和过期时间    token = generate_jwt_token(user_id=request.username)    expire_seconds = 7200# 2小时# 计算过期时间戳    expires_at = time.time() + expire_secondsreturn {"access_token": token,"token_type""Bearer","expires_in": expire_seconds,"expires_at"int(expires_at),    }

这代码没问题啊expires_in返回的是7200,也就是2小时,表示token还有多久过期这是标准的OAuth2设计啊

但是文档说是“为负数时表示已过期”,这是什么鬼我完全理解不了

然后我就开始怀疑人生了难道是我代码哪里有bug?expire_seconds算错了?generate_jwt_token里面有什么我没注意到的逻辑?

我拿着这个文档和代码对比了半天,越看越觉得不对劲但又说不上来哪里有问题

产品经理还等着我回复,我压力很大


中间踩的坑:排查过程及其离谱

为了搞清楚到底哪里的问题,我先入为主地认为是代码问题,开始了漫长的排查

第一步:检查JWT生成的代码

defgenerate_jwt_token(user_id: str) -> str:    payload = {"sub": user_id,"exp": time.time() + 7200,  # 过期时间设置为2小时后"iat": time.time(),    }    token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")return token

也没问题啊,过期时间是2小时后,很正常

第二步:用Python实际调用一下接口,看看返回到底是什么

$ curl -X POST http://localhost:8000/api/v1/login \  -H "Content-Type: application/json" \  -d '{"username": "testuser", "password": "testpass"}'

返回结果:

{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","token_type":"Bearer","expires_in":7200,"expires_at":1747824567}

返回值完全正确expires_in是7200,正数不是负数

这时候我更懵了代码是对的,返回也是对的,但文档为什么说“为负数时表示已过期”

第三步:我开始怀疑是Claude生成的时候哪里弄错了

我还特意跑回去问Claude:“你为什么说expires_in可以是负数

Claude给我的回复是这样的:

根据常见的API设计规范,有一些系统会使用负数来表示token已经过期/无效的状态,这是一种常见的约定...

我看到这条回复的时候人都麻了这 ai 在说什么这是它自己编的规范吧

我马上去查了我们系统的其他接口,还问了问组里有经验的同事大家用的都是正数表示剩余有效时间,从来没人用过负数

到这一步我才终于意识到:**这不是代码的问题,这是Claude生成的文档有幻觉**


最后怎么解决的:重新生成一遍,这次加了提示词约束

明确了问题所在之后,我就让Claude重新生成了一遍这次我在prompt 里加了一些约束:

请根据以下FastAPI代码生成OpenAPI格式的JSON文档。注意事项:1. 请严格按照代码中实际的返回值进行描述,不要添加你的推测2. expires_in 表示token的剩余有效时间,单位为秒,始终为正整数3. 只描述代码中实际存在的字段,不要自行添加字段4. 如果某个字段的含义你不确定,请标记为"待确认",不要猜测

这次生成的文档就没问题了:

{"/api/v1/login":{"post":{"summary":"用户登录","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}}}}}},"responses":{"200":{"description":"登录成功","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string","description":"访问令牌,用于后续接口认证"},"token_type":{"type":"string","description":"令牌类型,固定为'Bearer'"},"expires_in":{"type":"integer","description":"访问令牌的剩余有效时间,单位为秒"},"expires_at":{"type":"integer","description":"访问令牌的过期时间戳"}}}}}}}}}}

这次好多了,至少expires_in的描述是正确的——“访问令牌的剩余有效时间,单位为秒”

不过我还是不太放心,专门做了一个脚本来验证接口返回和文档是否一致:

#!/usr/bin/env python3"""验证API文档与实际接口返回值的一致性"""import requestsimport jsonBASE_URL = "http://localhost:8000"defverify_login_endpoint():"""测试登录接口的返回与文档描述是否一致"""    response = requests.post(f"{BASE_URL}/api/v1/login",        json={"username""test_verify""password""test123"}    )    data = response.json()# 验证必要字段存在    required_fields = ["access_token""token_type""expires_in""expires_at"]for field in required_fields:assert field in data, f"缺少字段: {field}"# 验证expires_in是正数if data["expires_in"] <= 0:print(f"[错误] expires_in应为正数,实际值: {data['expires_in']}")returnFalseprint(f"[验证通过] expires_in={data['expires_in']} (有效剩余时间)")print(f"[验证通过] expires_at={data['expires_at']} (过期时间戳)")returnTrueif __name__ == "__main__":    result = verify_login_endpoint()if result:print("\n✓ API文档与实际接口返回一致")else:print("\n✗ 验证失败,请检查API实现")        exit(1)

运行结果:

$ python verify_api.py[验证通过] expires_in=7200 (有效剩余时间)[验证通过] expires_at=1747827891 (过期时间戳)✓ API文档与实际接口返回一致

好了,总算是把这个问题解决了


这件事带给我的思考

这次排查虽然走了弯路,但如果重来一次,我会这样做:

  1. 1. 先不管文档,自己跑一遍接口,看实际的返回是什么
  2. 2. 用返回的值和文档对比
  3. 3. 发现不一致就直接问AI:“为什么你写的描述和实际返回不一样?”
  4. 4. 让AI解释它的理由,如果它的理由涉及到它“推测”的规范,就要格外警惕

而不是像我之前那样,先入为主地怀疑代码有问题


现在文档已经修正好了交给了产品经理,虽然耽误了一下午的时间,但至少没有造成更大的问题

回头想想还是很庆幸产品经理多问了那么一句,不然这个错误的文档流出去,后续还不知道会出什么乱子

这件事也算给我提了个醒:AI是个很好的工具,但你得会用用对了效率确实高,用错了就是一个坑

下次再让AI生成重要文档,我一定会先自己验证一遍

类似的问题,欢迎在评论区留言分享,大家一起交流避坑啊!