上一篇博客我完成了 AI Agent 的基础调用,跑通了第一个 API。但是上一篇博客我只做了一个模版类型的Prompt用来测试我的api调用是否成功,并进行简单功能的测试。在一个完善的智能OJ平台上,需要处理的类型有很多种,所以这一篇,我来做多场景的 Prompt 模板。

一、本篇目标

第一篇博客我完成了:

  • AI Agent 基础工作流设计

  • 通义千问 API 调用

  • 第一个 Prompt 模板(针对 Wrong Answer)

但实际 OJ 平台中,判题结果有很多种:Wrong Answer、Compile Error、Time Limit Exceeded、Runtime Error、Memory Limit Exceeded、Accepted

不同错误,用户想知道的东西不一样:

判题结果 用户想知道
Wrong Answer 逻辑哪里错了?
Compile Error 语法哪里写错了?
Time Limit Exceeded 哪里太慢了?怎么优化?
Runtime Error 哪里崩溃了?
Memory Limit Exceeded 哪里占内存太多?
Accepted 还能更好吗?

所以本篇的目标是:针对 6 种判题结果,设计 6 种不同的 Prompt 模板,让 AI 给出更有针对性的辅导。

二、6 种 Prompt 模板设计

2.1 设计思路

每种模板的核心区别在于:

  • 问的问题不同:WA 问逻辑,CE 问语法,TLE 问复杂度……

  • 输出的侧重点不同:TLE 必须分析时间复杂度,RE 必须分析异常类型

2.2 模板代码

上次的WA模版也润色了一下

// 1. Wrong Answer 模板
func buildWAPrompt(title, desc, code, errorMsg string) string {
	return fmt.Sprintf(`你是一个算法学习辅导老师。用户的代码提交结果是 Wrong Answer(答案错误)。

【题目信息】
- 标题:%s
- 描述:%s

【用户代码】
%s

【错误信息】
%s

请按以下格式输出(每部分控制在3-4行,不要重复):
1. 问题定位:用户的代码逻辑哪里出了问题?是否考虑了边界条件?
2. 原因分析:为什么会出现这个错误?请结合具体测试样例说明。
3. 改进方向:修改代码的思路是什么?需要注意哪些边界情况?

注意:不要直接给出完整代码,只提供思路引导。`,
		title, desc, code, errorMsg)
}

// 2. Compile Error 模板
func buildCEPrompt(title, desc, code, errorMsg string) string {
	return fmt.Sprintf(`你是一个算法学习辅导老师。用户的代码提交结果是 Compile Error(编译错误)。

【题目信息】
- 标题:%s
- 描述:%s

【用户代码】
%s

【编译错误信息】
%s

请按以下格式输出(每部分控制在3-4行,不要重复):
1. 问题定位:编译错误具体指向哪一行代码?是什么类型的语法错误?
2. 原因分析:为什么会出现这个编译错误?语法规则是怎样的?
3. 改进方向:如何修改代码才能通过编译?

注意:针对编译错误信息中的具体提示进行分析。`,
		title, desc, code, errorMsg)
}

// 3. Time Limit Exceeded 模板
func buildTLEPrompt(title, desc, code, errorMsg string) string {
	return fmt.Sprintf(`你是一个算法学习辅导老师。用户的代码提交结果是 Time Limit Exceeded(超时)。

【题目信息】
- 标题:%s
- 描述:%s

【用户代码】
%s

【超时信息】
%s

请按以下格式输出(每部分控制在3-4行,不要重复):
1. 问题定位:当前代码的时间复杂度是多少?哪部分逻辑最耗时?
2. 原因分析:为什么当前的算法会超时?数据规模下为什么不可行?
3. 改进方向:如何优化时间复杂度?建议使用什么算法或数据结构?

注意:请分析时间复杂度(如 O(n²)、O(2ⁿ) 等),给出具体的优化思路。`,
		title, desc, code, errorMsg)
}

// 4. Runtime Error 模板
func buildREPrompt(title, desc, code, errorMsg string) string {
	return fmt.Sprintf(`你是一个算法学习辅导老师。用户的代码提交结果是 Runtime Error(运行时错误)。

【题目信息】
- 标题:%s
- 描述:%s

【用户代码】
%s

【运行时错误信息】
%s

请按以下格式输出(每部分控制在3-4行,不要重复):
1. 问题定位:运行时错误可能发生在哪一行?是什么类型的错误?
2. 原因分析:为什么会触发这个运行时错误?
3. 改进方向:如何修改代码避免这个错误?

注意:常见错误类型:数组越界、除零错误、空指针、栈溢出、非法内存访问。`,
		title, desc, code, errorMsg)
}

// 5. Memory Limit Exceeded 模板
func buildMLEPrompt(title, desc, code, errorMsg string) string {
	return fmt.Sprintf(`你是一个算法学习辅导老师。用户的代码提交结果是 Memory Limit Exceeded(内存超限)。

【题目信息】
- 标题:%s
- 描述:%s

【用户代码】
%s

【内存超限信息】
%s

请按以下格式输出(每部分控制在3-4行,不要重复):
1. 问题定位:当前代码的空间复杂度是多少?哪部分数据结构占用内存最多?
2. 原因分析:为什么内存使用会超限?
3. 改进方向:如何优化空间复杂度?能否使用更省内存的数据结构?

注意:请分析空间复杂度(如 O(n²)、O(n) 等)。`,
		title, desc, code, errorMsg)
}

// 6. Accepted 模板
func buildACPrompt(title, desc, code, errorMsg string) string {
	return fmt.Sprintf(`你是一个算法学习辅导老师。用户的代码已通过 Accepted(通过了所有测试用例)。

【题目信息】
- 标题:%s
- 描述:%s

【用户代码】
%s

【判题信息】
%s

请按以下格式输出(每部分控制在3-4行,不要重复):
1. 复杂度分析:当前代码的时间和空间复杂度分别是多少?
2. 优化建议:如果有更好的解法,请介绍一下思路。
3. 举一反三:这道题还可以延伸到哪些类似题目?

注意:即使代码通过了,也可以给出优化建议。`,
		title, desc, code, errorMsg)
}

2.3 模板分发函数

设计一个switch-case来对不同的判题结果进行处理,这样也方便后期进行对接

func BuildPromptByResult(problemTitle, problemDesc, userCode, resultType, errorMsg string) string {
	switch resultType {
	case "Wrong Answer", "WA":
		return buildWAPrompt(problemTitle, problemDesc, userCode, errorMsg)
	case "Compile Error", "CE":
		return buildCEPrompt(problemTitle, problemDesc, userCode, errorMsg)
	case "Time Limit Exceeded", "TLE":
		return buildTLEPrompt(problemTitle, problemDesc, userCode, errorMsg)
	case "Runtime Error", "RE":
		return buildREPrompt(problemTitle, problemDesc, userCode, errorMsg)
	case "Memory Limit Exceeded", "MLE":
		return buildMLEPrompt(problemTitle, problemDesc, userCode, errorMsg)
	case "Accepted", "AC":
		return buildACPrompt(problemTitle, problemDesc, userCode, errorMsg)
	default:
		return buildDefaultPrompt(problemTitle, problemDesc, userCode, resultType, errorMsg)
	}
}

三、测试

上次用的是ai生成的一个两数之和的题目,这次去洛谷找一道题来测试,可能会比较有代表性

题目--P1134 [USACO3.2] 阶乘问题

写一个程序,计算 N (1≤N≤5×10^7) 阶乘的最右边的非零位的值。

3.1 WA 56分代码

problemTitle := "阶乘问题"
	problemDesc := "写一个程序,计算 N 阶乘的最右边的非零位的值。"
	userCode := `#include<iostream>
#include<cstdio>
using namespace std;
int n;
unsigned long long ans=1;
int main()
{
    cin>>n;
	for(int i=2;i<=n;i++)
	{
		ans*=i;
		while(ans%10000==0)ans/=10000;
		ans%=10000;
	}
	while(ans%10==0)ans/=10;
	ans%=10;
	cout<<ans;
    return 0;
}`

测试结果

3.2 TLE

懒得贴代码了,就在上面代码中间加了个while(1)

测试结果

3.3 AC(题解)

	problemTitle := "阶乘问题"
	problemDesc := "写一个程序,计算 N 阶乘的最右边的非零位的值。"
	userCode := `#include <cstdio>
using namespace std;
int n,ans=1;
int a[4]= {6,8,4,2};
int main() {
    scanf("%d",&n);
    while (n>0) {
        for (int i=1; i<=n%10;++i)
            if (i!=5) ans=ans*i%10;
        n=n/5;
        ans=ans*a[n%4]%10;
    }
    printf("%d",ans);
    return 0;
}
`

测试结果

3.4 其他的还有小总结

就不多说了,其他的也都大差不差,没有什么很明显的问题,就不一一列举了。

感觉有点不好的地方是,一个是我其实想让ai大讲特讲个三四行,但是感觉生成结果有点简略,后面连起来总不能前端也返回简单这几个字,那还看个啥呢,下次会顺便给prompt加两句话让大模型讲细一点。

另一个是感觉大模型的分析其实有点太“全面”了,比如那个超时的问题它已经看到那个while是会堵死的,但是它还会去分析其他代码的复杂度,并且把这些都并列起来说,但我感觉应该重点突出这个while的问题,因为TLE只因为这个原因,别的顺带讲讲就OK,这样也不知道是好是坏,但现在也不知道怎么解决,在prompt加几句约束不知道能不能行。

四、遇到的问题

和上次一样,老是runrunrunrun好多次才能正常运行,下次不用vscode写试一下会不会正常

感觉要成功运行一次要run个十几遍吧,而且每次调api都等个两分钟,我本来设置的60s的超时时间居然完全不够用,返回调用失败我还以为是代码哪里有问题。这篇实际上就是拓展一下prompt的类型,整个下来我感觉我实际上没做什么事情,但是就是花了一大把时间去测试,真的劳累。

五、小结 还有下一篇内容

本篇完成了 6 种判题结果的 Prompt 模板设计,让 AI 能够针对不同错误类型给出差异化的辅导。

下一篇将进入 RAG 检索模块,让 AI 能引用知识库中的算法知识,进一步提高讲解的准确性。

现在才做两篇有点偷懒了,我真得快点做了

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐