作者:Laurel W
来源:Adobe
作为一名数据科学和数学老师,我其实不介意我的学生使用像 ChatGPT 这样的 LLM,只要它是用来辅助他们学习,而不是取代学习过程。加州理工学院的申请文书指南启发了我为编程和机器学习课制定 AI 使用政策:
哪些是加州理工申请文书中不道德的 AI 使用方式?
- 直接从 AI 生成器复制粘贴
- 依赖 AI 生成内容来列提纲或起草文书
- 用 AI 生成的内容替换你独特的声音和语气
- 翻译用其他语言写的文书
哪些是加州理工申请文书中道德的 AI 使用方式?
- 使用 Grammarly 或 Microsoft Editor 这类 AI 工具检查语法拼写
- 用 AI 生成问题或练习题,帮助启动头脑风暴
- 用 AI 来研究申请流程
如果你还在想你使用 AI 是否道德,问问自己:你请一位值得信赖的大人做同样的事,合适吗?比如请老师帮你改语法错拼写错?当然可以!但让老师帮你写一篇文书草稿,然后你稍微改改就交了?绝对不行。
话虽如此,最近我收到了一些代码作业,一看就完全是 AI 写的,于是我整理了一些"AI 征兆"。当然,人类和 AI 写的代码现在越来越难分辨。但 ChatGPT / Claude / DeepSeek 这些生成的代码,还是有一些共同特征,一看就不对劲。
注释
我希望所有学生都能像 ChatGPT 那样写那么详细的注释吗?当然希望。但他们会吗?肯定不会。
🚩 注释过于详细或者风格怪异,是使用 AI 的信号。
比如,DeepSeek 生成的代码里你会看到用三引号写一段 docstring 来当注释,而不是用标准的 #,尽管那段 docstring 并没有说明参数或返回值:
def find_squares_adding_to_zero(mod):
"""Find two non-zero numbers a and b such that a^2 + b^2 ≡ 0 mod n."""
for a in range(1, mod): # Start from 1 to exclude a = 0
for b in range(a, mod): # Start from a to avoid redundant pairs
if (a2 + b2) % mod == 0:
return (a, b)
return None
我觉得这用来注释一行代码的方式很不自然,尤其是我在课上明确教的是用 # 来写单行注释,而这段也不是一个正经的 docstring。
注释里用特殊符号也可能是 AI 写的。除非是我写给很多人看的代码,我自己是不会去找像 "≡" 这样的符号来写注释的。我敢说我的学生大概也不会这么做。
Lambda 表达式
别误会------我喜欢 lambda 表达式,觉得它们是 Python 中很独特且有价值的功能。我认为 lambda 是用来写简洁、临时的小函数的,直接作为参数传给像 map()、filter() 或 sorted() 这种函数才合适。用得好很亮眼。但 lambda 表达式一旦滥用、用错地方,或者还没讲到就乱用,就是个警示。
🚩 lambda 用得不合时宜,说明设计不够认真,或者太依赖 AI。
比如,要是我在还没系统讲 lambda 表达式前,收到这么一份作业代码,那我肯定第一时间就怀疑是 ChatGPT 写的:
from functools import lru_cache
fib = (lambda f: (lambda x: f(f, x)))(lambda self, n:
n if n < 2 else self(self, n-1) + self(self, n-2))
Generate the first 10 Fibonacci numbers
fib_sequence = [fib(n) for n in range(10)]
print(fib_sequence)
这种写法根本不适合用 lambda,而且太复杂了,不可能是一个第一次学 Python 的学生自己写出来的。
库的使用
库导入的位置
🚩 有时候,LLM 会把 import 放在奇怪的位置(不是在文件最上面)。
这种情况我只见过几次,但如果你已经跟学生强调过 import 要放在开头或集中在一起,那这种写法就可疑了。
用了什么库:
🚩 用某个库完成其实不需要它的任务,尤其是没讲过的冷门库,也可能是 AI 写的迹象。
我们再看看上面那段 lambda 代码:
from functools import lru_cache
fib = (lambda f: (lambda x: f(f, x)))(lambda self, n:
n if n < 2 else self(self, n-1) + self(self, n-2))
Generate the first 10 Fibonacci numbers
fib_sequence = [fib(n) for n in range(10)]
print(fib_sequence)
如果你还没讲过 functools 这个库,那学生很可能是用 Google 或 LLM 才知道的。用这些工具探索库当然没问题,但也可能说明实现方式就是 AI 生成的。
命名和格式风格不一致
这个一看就懂。如果作业要求某个字段或变量要用特定命名,AI 写出来的代码往往会给出更泛、更"解释性"的名字,但反而不自然。比如,下面这段找所有小于 n 的素数的代码,一个普通学生可能不会写得这么工整、变量名这么"讲究":
def sieve_of_eratosthenes(limit):
"""Return a list of all prime numbers less than the given limit."""
if limit <= 2:
return []
Initialize a boolean array to track prime numbers
is_prime = [True] * limit
is_prime[0] = is_prime[1] = False # 0 and 1 are not primes
for num in range(2, int(limit**0.5) + 1):
if is_prime[num]:
Mark multiples of num as non-prime
for multiple in range(num * num, limit, num):
is_prime[multiple] = False
Collect all prime numbers
primes = [num for num, prime in enumerate(is_prime) if prime]
return primes
Example usage
limit = 50 # Change this value to find primes less than a different number
primes = sieve_of_eratosthenes(limit)
print(f"Primes less than {limit}: {primes}")
我自己可能会用 n 而不是 limit,函数名也会更随意些,比如叫 prime_finder。当然,一些特别讲究的学生也可能会写成这样,所以我一般是结合其他迹象一起判断是不是 AI 写的。
逻辑错误
逻辑错误纸面上是最明显的红旗。但实际上很难判断------到底是语言模型出错了,还是学生自己没理解透?
归根结底,LLM 是基于统计的模型,用训练数据学到的模式来预测下一个 token(比如字、词或子词)。它们擅长生成连贯、有上下文的文本,但并不真正理解、也不具备推理或算法思维。这导致它们在需要精确逻辑的任务上容易出错,比如解数学题或者写代码。有时候会给出看上去靠谱但其实错的答案,或者根本没搞清楚复杂的逻辑结构。比如我见过它们在数学题里索引错、没处理边界条件、甚至输出完全错误。
🚩 如果代码有逻辑错误或者推理错误,那可能是 AI 写的。
理想情况下,一个认真点的学生会先检查并修正这些错误再交作业。但实际情况是,很多代码交上来根本不能跑,或者输出就错了。
最后提醒一下,其实很难定一个硬性规则来判断是不是 AI 写的代码,所以我建议老师先别急着指责,而是带着好奇去了解学生的思路。如果我怀疑一个学生太依赖 AI,我可能会让他白板手写一个类似的题目,或者问问他对这个解法的理解。只要引导得当、细节到位,我希望未来能培养出的是会把 AI 当工具,而不是当拐杖的专业人士。