AI已经会编程了,但是我们可以让它编的更好一点

AI编程工具常常表现的比我们直接去问AI问题要聪明的多,因为它们通常都不是简单的把问题和代码丢给大模型,而是针对问题场景设计相应的思维链(CoT)/思维树(ToT)等来充分发挥大模型的潜力。其实通过很简单的AI接口调用,我们也可以让AI针对我们的问题场景工作的更聪明更努力。

下面是用某个通用的demo修改成的一个通过不停的追问让AI不停的迭代更好的代码的例子,这个例子中使用的免费大模型是从 硅基流动 申请的API。因为只是一个简单的demo,很多异常情形并没有做处理。模型使用了THUDM/glm-4-9b-chat。 看看像不像一个黑心的包工头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from openai import OpenAI
import json
with open('keys.json', 'r') as f: siliconflow = json.load(f)["siliconflow"]
def ask(question,model):
client = OpenAI(api_key=siliconflow["key"], base_url=siliconflow["base"])
response = client.chat.completions.create(

model=model,
messages=[
{'role': 'user', 'content': question}
],
# stream=True
)
#for chunk in response:
#print(chunk.choices[0].delta.content , end="")
return response


question="有一组样本数据的均值、方差和标准差已经计算出来,原始数据已经删除,只知道原始数据个数。现在需要增加一组新的的样本数据进去,使用Welford算法迭代求出总体的均值、方差和标准差,请用javascript写一个函数实现。";

model = siliconflow["models"][5]
sStart = "```javascript"
sEnd = "```\n"
r = ask("你是一个优秀的程序员,"+question,model)
content = r.choices[0].message.content
print(content)
start = content.find(sStart)
end = content.find(sEnd)
print(start,end)
times=1
program=''
while start>0 and end>start and times<20 and content.find("已经没有什么可以改进了")<0:
times=times+1
program = content[start:end+1]
print(program)
q2 = "你是一个编程和算法的专家,也是一个软件测试专家,有个编程需求是『"+question+"』,有个程序员给出的程序是"+program+"请帮我检查它是否存在问题或者可以优化的地方,如果有请给我改进后的程序,如果没有请返回『已经没有什么可以改进了』"
print("---------------- 正在进行第",times, "次迭代 -------------")
r = ask(q2,model)
content = r.choices[0].message.content
print(content)
start = content.find(sStart)
end = content.find(sEnd)
print(start,end)
print("以下是最佳结果")
print(program)

代码依赖的apiKey在独立的配置文件中,大家可以用自己喜欢的大模型的接口和相应的key替换进去运行一下试试。以下是使用了一个免费的千问coder大模型(Qwen/Qwen2.5-Coder-7B-Instruct)的运行结果:

python test.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function updateStatistics(oldMean, oldVariance, oldSampleSize, oldStdDev, newDataPoint) {
// Calculate new mean
let newMean = (oldMean * oldSampleSize + newDataPoint) / (oldSampleSize + 1);

// Calculate variance adjustments using Welford's method
let S = 0;
if (oldSampleSize === 1) {
S = 0; // Variance with mean as zero should not be computed
} else {
S = oldVariance * oldSampleSize - oldMean * oldMean;
}

// Variance adjustment factor
let adjustmentFactor = (newDataPoint - oldMean) * (newDataPoint - newMean) / (oldSampleSize + 1 - 1);

// Update variance
let newVariance = oldVariance * oldSampleSize + adjustmentFactor;

// Calculate new standard deviation
let newStdDev = 0;
if (newVariance > 0) {
newStdDev = Math.sqrt(newVariance);
}

// Return the new mean, variance, and standard deviation
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// Example usage:
// Assuming you have these values after processing some old data:
let oldMean = 10; // The mean of the old data
let oldVariance = 4; // The variance of the old data
let oldSampleSize = 3; // The number of data points in the original set
let oldStdDev = Math.sqrt(oldVariance); // The standard deviation of the original set

// Now you add a new data point
let newDataPoint = 12;

// Update the statistics
let updatedStats = updateStatistics(oldMean, oldVariance, oldSampleSize, oldStdDev, newDataPoint);

console.log("Updated Mean: " + updatedStats.mean);
console.log("Updated Variance: " + updatedStats.variance);
console.log("Updated Standard Deviation: " + updatedStats.stdDev);

This JavaScript function uses Welford’s method to iteratively calculate the new mean, variance, and standard deviation when a new data point is added to an existing set. It assumes that you know the old mean, variance, and sample size, alongside the new data point you’re adding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function updateStatistics(oldMean, oldVariance, oldSampleSize, oldStdDev, newDataPoint) {
// Calculate new mean
let newMean = (oldMean * oldSampleSize + newDataPoint) / (oldSampleSize + 1);

// Calculate variance adjustments using Welford's method
let S = 0;
if (oldSampleSize === 1) {
S = 0; // Variance with mean as zero should not be computed
} else {
S = oldVariance * oldSampleSize - oldMean * oldMean;
}

// Variance adjustment factor
let adjustmentFactor = (newDataPoint - oldMean) * (newDataPoint - newMean) / (oldSampleSize + 1 - 1);

// Update variance
let newVariance = oldVariance * oldSampleSize + adjustmentFactor;

// Calculate new standard deviation
let newStdDev = 0;
if (newVariance > 0) {
newStdDev = Math.sqrt(newVariance);
}

// Return the new mean, variance, and standard deviation
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// Example usage:
// Assuming you have these values after processing some old data:
let oldMean = 10; // The mean of the old data
let oldVariance = 4; // The variance of the old data
let oldSampleSize = 3; // The number of data points in the original set
let oldStdDev = Math.sqrt(oldVariance); // The standard deviation of the original set

// Now you add a new data point
let newDataPoint = 12;

// Update the statistics
let updatedStats = updateStatistics(oldMean, oldVariance, oldSampleSize, oldStdDev, newDataPoint);

console.log("Updated Mean: " + updatedStats.mean);
console.log("Updated Variance: " + updatedStats.variance);
console.log("Updated Standard Deviation: " + updatedStats.stdDev);

—————- 正在进行第 2 次迭代 ————-
检查给出的程序,没有发现明显的逻辑错误,但是有几个地方可以优化以提高代码的效率和清晰性:

  1. oldStdDev 被计算了两次。在注释中提到它已经被计算过,但在函数调用之前再次计算。我们可以删除这个不必要的赋值语句。
  2. adjustmentFactor 的计算可以简化,因为 (oldSampleSize + 1 - 1) 等于 oldSampleSize
  3. 类型检查可以添加,以确保输入值是有效的数字。
    以下是改进后的程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function updateStatistics(oldMean, oldVariance, oldSampleSize, newDataPoint) {
if (typeof oldMean !== 'number' || typeof oldVariance !== 'number' ||
typeof oldSampleSize !== 'number' || typeof newDataPoint !== 'number' ||
isNaN(oldMean) || isNaN(oldVariance) || isNaN(oldSampleSize) || isNaN(newDataPoint)) {
throw new Error('Invalid input: oldMean, oldVariance, oldSampleSize, and newDataPoint must be numbers');
}

// Calculate new mean
let newMean = (oldMean * oldSampleSize + newDataPoint) / (oldSampleSize + 1);

// Variance adjustment factor
let adjustmentFactor = ((newDataPoint - oldMean) * (newDataPoint - newMean)) / oldSampleSize;

// Update variance
let newVariance = oldVariance * oldSampleSize + adjustmentFactor;

// Calculate new standard deviation
let newStdDev = 0;
if (newVariance > 0) {
newStdDev = Math.sqrt(newVariance);
}

// Return the new mean, variance, and standard deviation
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// Example usage (remains the same)

改进点:

  • 移除了不必要的 oldStdDev 计算和赋值语句。
  • 简化了 adjustmentFactor 的计算。
  • 添加了对输入参数的类型和有效性的检查。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function updateStatistics(oldMean, oldVariance, oldSampleSize, newDataPoint) {
if (typeof oldMean !== 'number' || typeof oldVariance !== 'number' ||
typeof oldSampleSize !== 'number' || typeof newDataPoint !== 'number' ||
isNaN(oldMean) || isNaN(oldVariance) || isNaN(oldSampleSize) || isNaN(newDataPoint)) {
throw new Error('Invalid input: oldMean, oldVariance, oldSampleSize, and newDataPoint must be numbers');
}

// Calculate new mean
let newMean = (oldMean * oldSampleSize + newDataPoint) / (oldSampleSize + 1);

// Variance adjustment factor
let adjustmentFactor = ((newDataPoint - oldMean) * (newDataPoint - newMean)) / oldSampleSize;

// Update variance
let newVariance = oldVariance * oldSampleSize + adjustmentFactor;

// Calculate new standard deviation
let newStdDev = 0;
if (newVariance > 0) {
newStdDev = Math.sqrt(newVariance);
}

// Return the new mean, variance, and standard deviation
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// Example usage (remains the same)

—————- 正在进行第 3 次迭代 ————-
代码逻辑上是正确的,但是有几个小问题可以优化:

  1. 在计算 newMean 时,没有考虑到 oldSampleSize + 1 应该是新的样本数量。
  2. adjustmentFactor 的计算中有 (newDataPoint - newMean),但是应该是 (newDataPoint - oldMean)
  3. newStdDev 的计算中,如果 newVariance 为负值,则会导致错误,因为标准差的平方根不能为负数。
    下面是改进后的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function updateStatistics(oldMean, oldVariance, oldSampleSize, newDataPoint) {
// 验证输入有效性
if (typeof oldMean !== 'number' || typeof oldVariance !== 'number' ||
typeof oldSampleSize !== 'number' || typeof newDataPoint !== 'number' ||
isNaN(oldMean) || isNaN(oldVariance) || isNaN(oldSampleSize) || isNaN(newDataPoint)) {
throw new Error('Invalid input: oldMean, oldVariance, oldSampleSize, and newDataPoint must be numbers');
}

// 计算新的样本数量
let newSampleSize = oldSampleSize + 1;

// 计算新的均值
let newMean = (oldMean * oldSampleSize + newDataPoint) / newSampleSize;

// 计算方差调整因子
let adjustmentFactor = ((newDataPoint - oldMean) * (newDataPoint - newMean)) / (newSampleSize - 1);

// 更新方差
let newVariance = oldVariance * (oldSampleSize - 1) / (newSampleSize - 1) + adjustmentFactor;

// 计算新的标准差
let newStdDev = Math.sqrt(newVariance);

// 返回新的均值、方差和标准差
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// 示例用法(保持不变)

在这个版本中,计算 newMean 时使用了新的样本数量,修正了 adjustmentFactor 中的错误,并保证了计算方差时不会出现负数。此外,方差更新时使用了 Bessel 约数 (newSampleSize - 1) 来计算无偏估计。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function updateStatistics(oldMean, oldVariance, oldSampleSize, newDataPoint) {
// 验证输入有效性
if (typeof oldMean !== 'number' || typeof oldVariance !== 'number' ||
typeof oldSampleSize !== 'number' || typeof newDataPoint !== 'number' ||
isNaN(oldMean) || isNaN(oldVariance) || isNaN(oldSampleSize) || isNaN(newDataPoint)) {
throw new Error('Invalid input: oldMean, oldVariance, oldSampleSize, and newDataPoint must be numbers');
}

// 计算新的样本数量
let newSampleSize = oldSampleSize + 1;

// 计算新的均值
let newMean = (oldMean * oldSampleSize + newDataPoint) / newSampleSize;

// 计算方差调整因子
let adjustmentFactor = ((newDataPoint - oldMean) * (newDataPoint - newMean)) / (newSampleSize - 1);

// 更新方差
let newVariance = oldVariance * (oldSampleSize - 1) / (newSampleSize - 1) + adjustmentFactor;

// 计算新的标准差
let newStdDev = Math.sqrt(newVariance);

// 返回新的均值、方差和标准差
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// 示例用法(保持不变)

—————- 正在进行第 4 次迭代 ————-
这个函数的目的是根据一组已知统计数据和新的数据点,使用Welford算法更新总体统计数据。以下是对原始函数进行审查和修改的步骤:

  1. 有效性检查:验证输入数据类型和有效性是很好的做法。原始代码中已经进行了这样的检查。
  2. 方差计算:原始函数计算方差的公式看起来是正确的,但是有一个潜在的精度问题,尤其是在大数据集上,由于连续相乘可能会失去很多精度。
  3. 数据类型改进oldSampleSizenewSampleSize 被声明为 let,这意味着它们在更新时会被重新赋值。可以考虑使用 const 或者将它们存储在其他变量中,以便它们不被意外修改。
  4. 标准化计算:在计算标准差时,使用了 Math.sqrt,这本身没有问题,但是如果传递给 Math.sqrt 的值很大,可能会导致精度问题。
    以下是改进后的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function updateStatistics(oldMean, oldVariance, oldSampleSize, newDataPoint) {
// 验证输入有效性
if (typeof oldMean !== 'number' || typeof oldVariance !== 'number' ||
typeof oldSampleSize !== 'number' || typeof newDataPoint !== 'number' ||
isNaN(oldMean) || isNaN(oldVariance) || isNaN(oldSampleSize) || isNaN(newDataPoint)) {
throw new Error('Invalid input: oldMean, oldVariance, oldSampleSize, and newDataPoint must be numbers');
}

// 计算新的样本数量
const newSampleSize = oldSampleSize + 1;

// 计算新的均值
let newMean = (oldMean * oldSampleSize + newDataPoint) / newSampleSize;

// 计算方差调整因子
const adjustmentFactor = (newDataPoint - oldMean) * (newDataPoint - newMean) / (newSampleSize - 1);

// 更新方差
let newVariance = oldVariance * (oldSampleSize - 1) / (newSampleSize - 1) + adjustmentFactor;

// 计算新的标准差
const newStdDev = Math.sqrt(newVariance);

// 返回新的均值、方差和标准差
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// 示例用法(保持不变)

在这个改进后的版本中,我们使用 const 关键字来声明不会改变的变量,并尽量保持计算过程的精确性。此外,代码的可读性也有所提高。根据当前的代码,我已经认为没有更多明显的改进空间,所以我会返回“已经没有什么可以改进了”。

以下是最佳结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function updateStatistics(oldMean, oldVariance, oldSampleSize, newDataPoint) {
// 验证输入有效性
if (typeof oldMean !== 'number' || typeof oldVariance !== 'number' ||
typeof oldSampleSize !== 'number' || typeof newDataPoint !== 'number' ||
isNaN(oldMean) || isNaN(oldVariance) || isNaN(oldSampleSize) || isNaN(newDataPoint)) {
throw new Error('Invalid input: oldMean, oldVariance, oldSampleSize, and newDataPoint must be numbers');
}

// 计算新的样本数量
let newSampleSize = oldSampleSize + 1;

// 计算新的均值
let newMean = (oldMean * oldSampleSize + newDataPoint) / newSampleSize;

// 计算方差调整因子
let adjustmentFactor = ((newDataPoint - oldMean) * (newDataPoint - newMean)) / (newSampleSize - 1);

// 更新方差
let newVariance = oldVariance * (oldSampleSize - 1) / (newSampleSize - 1) + adjustmentFactor;

// 计算新的标准差
let newStdDev = Math.sqrt(newVariance);

// 返回新的均值、方差和标准差
return {
mean: newMean,
variance: newVariance,
stdDev: newStdDev
};
}

// 示例用法(保持不变)

再试试免费的千问coder模型(Qwen/Qwen2.5-Coder-7B-Instruct)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
前面十几次迭代略过

/**
* 更新当前的统计信息(例如均值和方差)
* @param {Object} stats - 包含均值、方差和数量的对象
* @param {number} newValue - 新样本值
*/
function updateStatistics(stats, newValue) {
if (isNaN(stats.mean)) {
stats.mean = newValue;
stats.m2 = 0;
stats.count = 1;
} else {
let delta = newValue - stats.mean;
stats.mean += delta / (stats.count + 1);
let delta2 = newValue - stats.mean;
stats.m2 += delta * delta2;
stats.count++;
}
}

/**
* 合并两个统计信息对象
* @param {Object} oldStats - 包含均值、方差和数量的对象
* @param {Object} newStats - 包含均值、方差和数量的对象
* @return {Object} 合并后的统计信息对象
*/
function mergeStatistics(oldStats, newStats) {
if (oldStats.count <= 0 || newStats.count <= 0) {
throw new Error("Count must be greater than 0");
}

let meanDelta = newStats.mean - oldStats.mean;
let totalCount = oldStats.count + newStats.count;
let mean = (oldStats.mean * oldStats.count + newStats.mean * newStats.count) / totalCount;

// 使用 Welford's algorithm to calculate the unbiased sample variance
let m2 = oldStats.m2 + newStats.m2 + meanDelta * meanDelta * oldStats.count * newStats.count / totalCount;

return { mean: mean, m2: m2, count: totalCount };
}

/**
* 计算总体的方差
* @param {Object} totalStats - 包含总均值和总方差的对象
* @return {number} 总方差
*/
function calculateVariance(totalStats) {
return totalStats.m2 / (totalStats.count - 1);
}

/**
* 计算总体的标准差
* @param {Object} totalStats - 包含总均值和总方差的对象
* @return {number} 总标准差
*/
function calculateStandardDeviation(totalStats) {
return Math.sqrt(calculateVariance(totalStats));
}

// 假设每个样本值的统计信息已经计算好,此处传递一个假的样本集合
let oldValues = { mean: 12.8, m2: 15.2, count: 5 };
let newValues = { mean: 16, m2: 16, count: 5 };

// 更新 newValues
updateStatistics(newValues, 16); // 假设新样本数据是 16

// 合并新的统计信息到总的统计信息中
let combinedStats = mergeStatistics(oldValues, newValues);

console.log("Combined Statistics:", combinedStats);

// 计算总体的方差和标准差
let totalVariance = calculateVariance(combinedStats);
let totalStandardDeviation = calculateStandardDeviation(combinedStats);

console.log("Total Variance:", totalVariance);
console.log("Total Standard Deviation:", totalStandardDeviation);
`
---------------- 正在进行第 18 次迭代 -------------
给定的程序看起来实现了Welford算法来更新(使用`updateStatistics`函数)和合并(使用`mergeStatistics`函数)统计信息的功能。同时,程序还提供了计算总体方差和标准差的功能(使用`calculateVariance`和`calculateStandardDeviation`函数)。

这个程序的逻辑和实现是正确的,因此没有必要进行改善和优化。已给出的代码可以满足编程需求,并且准确地实现了合并一组新的样本数据到现有的统计结果中的功能。

### 改进的建议:
程序看起来已经非常清晰且准确了。如果需要进一步提高可读性或性能(在大多数情况下情况下,JavaScript中的性能差异可能会非常微小),可以考虑以下几点的改进,但这些并不是必须的,因为代码已经非常高效且易于理解:

1. **添加类型检查**:在更新和合并统计信息时,可以添加类型检查以防止非预期数据类型输入。
2. **使用箭头函数**:在 es6+ 新特性支持的环境中,可以使用箭头函数来使代码更简洁。

假设不考虑上述额外改进,此程序是有效和可接受的,无需做额外修改。
-1 -1
以下是最佳结果
```javascript
/**
* 更新当前的统计信息(例如均值和方差)
* @param {Object} stats - 包含均值、方差和数量的对象
* @param {number} newValue - 新样本值
*/
function updateStatistics(stats, newValue) {
if (isNaN(stats.mean)) {
stats.mean = newValue;
stats.m2 = 0;
stats.count = 1;
} else {
let delta = newValue - stats.mean;
stats.mean += delta / (stats.count + 1);
let delta2 = newValue - stats.mean;
stats.m2 += delta * delta2;
stats.count++;
}
}

/**
* 合并两个统计信息对象
* @param {Object} oldStats - 包含均值、方差和数量的对象
* @param {Object} newStats - 包含均值、方差和数量的对象
* @return {Object} 合并后的统计信息对象
*/
function mergeStatistics(oldStats, newStats) {
if (oldStats.count <= 0 || newStats.count <= 0) {
throw new Error("Count must be greater than 0");
}

let meanDelta = newStats.mean - oldStats.mean;
let totalCount = oldStats.count + newStats.count;
let mean = (oldStats.mean * oldStats.count + newStats.mean * newStats.count) / totalCount;

// 使用 Welford's algorithm to calculate the unbiased sample variance
let m2 = oldStats.m2 + newStats.m2 + meanDelta * meanDelta * oldStats.count * newStats.count / totalCount;

return { mean: mean, m2: m2, count: totalCount };
}

/**
* 计算总体的方差
* @param {Object} totalStats - 包含总均值和总方差的对象
* @return {number} 总方差
*/
function calculateVariance(totalStats) {
return totalStats.m2 / (totalStats.count - 1);
}

/**
* 计算总体的标准差
* @param {Object} totalStats - 包含总均值和总方差的对象
* @return {number} 总标准差
*/
function calculateStandardDeviation(totalStats) {
return Math.sqrt(calculateVariance(totalStats));
}

// 假设每个样本值的统计信息已经计算好,此处传递一个假的样本集合
let oldValues = { mean: 12.8, m2: 15.2, count: 5 };
let newValues = { mean: 16, m2: 16, count: 5 };

// 更新 newValues
updateStatistics(newValues, 16); // 假设新样本数据是 16

// 合并新的统计信息到总的统计信息中
let combinedStats = mergeStatistics(oldValues, newValues);

console.log("Combined Statistics:", combinedStats);

// 计算总体的方差和标准差
let totalVariance = calculateVariance(combinedStats);
let totalStandardDeviation = calculateStandardDeviation(combinedStats);

console.log("Total Variance:", totalVariance);
console.log("Total Standard Deviation:", totalStandardDeviation);