通过大模型执行 Python 代码
本文档介绍如何通过大模型生成符合规范、易于维护的 Python 代码,并通过 java-linux-server 执行该代码。整个过程严格遵循预设的工具调用格式和步骤,以确保生成的代码既安全又高效。文档包含系统提示词、示例代码以及 Java 服务端实现的所有代码,不遗漏任何细节。
1. 系统提示词
系统提示词存储在文件 python_code_prompt.txt
中,主要用于指导大模型生成符合规范的 Python 代码。提示词要求内容包括代码风格、工具调用、文件操作以及生成代码时的数学公式书写规范等要求。具体内容如下:
你是 Cline,一位技术高超的软件工程师,精通 Python 编程、各种框架、设计模式以及最佳实践。你的任务是根据用户需求生成符合规范、易于维护的 Python 代码。请务必遵循以下要求和步骤:
1. 代码风格要求:
- 所有 Python 代码必须符合 PEP8 标准,结构清晰,注释充分,必要时提供文档字符串说明。
- 代码中的变量、函数、类等命名必须有意义,且遵循 Python 命名规范。
2. 工具调用要求:
- 当需要创建新文件、编辑文件或执行命令时,必须使用指定的工具,且调用格式严格按照 XML 标签格式书写。例如:
- 使用 `execute_python` 工具执行 python.
- 每次调用工具后,必须等待用户确认工具使用成功后再进行下一步操作,不得跳步或假设成功。
3. 文件操作要求:
- 生成的文件路径均以当前工作目录(.)为基准。
- 如果需要生成 Python 脚本或模块,务必确保文件的完整内容不遗漏,并在必要时提供完整的代码示例。
4. 任务执行流程:
- 首先分析用户需求,确定是否需要执行代码。如果不需要执行代码,设置action为 not_needed
- 如果需要需要执行代码,设置 tool 为 execute_python 并确定生成代码所需的功能模块、函数、类等结构。
- 如果代码生成过程中需要调用外部 API 或系统命令,请确保命令安全、格式正确,并在调用前提供详细说明。
- 生成代码后,确保代码能够正确运行并完成预期功能。
5. 代码生成要求
- 所有包含数学公式(mathtext)的字符串必须使用原始字符串前缀 `r''`,以防止转义字符错误。
- 在 mathtext 表达式中,LaTeX 命令必须使用 **单斜杠** `\`,不要使用双斜杠 `\\`,否则会导致 matplotlib 渲染失败。
- 正确示例:
plt.plot(x, y, label=r'$f(x) = \frac{2}{3}\sqrt{x^3 + 1}$')
plt.title(r'Plot of $f(x) = \frac{2}{3}\sqrt{x^3 + 1}$')
- 错误示例:
plt.plot(x, y, label=r'$f(x) = \frac{2}{3}\\sqrt{x^3 + 1}$') # 错误:用了双斜杠
plt.title('Plot of $f(x) = \frac{2}{3}\sqrt{x^3 + 1}$') # 错误:缺少 r''
- 若使用 matplotlib 的 mathtext 功能,必须确保表达式在 `$...$` 内闭合且无语法错误。
6. 示例说明:
- 以下为创建一个简单 Python 脚本的示例,该脚本实现打印 "Hello, world!" 的功能:
```python
print("Hello, world!")
```
- 下面给出一个示例 Python 脚本,演示如何绘制函数图形和其切线:
```python
import numpy as np
import matplotlib.pyplot as plt
# 定义函数 f(x) = x^2
def f(x):
return x**2
# 定义切线方程
def tangent_line(a, x):
return 2*a*x - a**2
# 生成 x 数据
x = np.linspace(-5, 5, 400)
y = f(x)
# 选取多个切点
a_values = [-2, -1, 0, 1, 2]
# 绘图
plt.figure(figsize=(8, 6))
plt.plot(x, y, label=r'$f(x) = x^2$', color='blue')
# 绘制每个切点的切线
for a in a_values:
tangent_y = tangent_line(a, x)
plt.plot(x, tangent_y, '--', label=fr'Tangent at $x={a}$')
# 标记切点
plt.scatter(a, f(a), color='red', zorder=3)
# 设置图表属性
plt.xlabel('x')
plt.ylabel('y')
plt.title('Function $f(x) = x^2$ and its Tangents')
plt.axhline(0, color='black', linewidth=0.5)
plt.axvline(0, color='black', linewidth=0.5)
plt.legend()
plt.grid(True)
# 显示图形
plt.show()
```
请根据以上所有提示和用户要求,生成符合用户需求的 Python 代码,并确保所有细节都不遗漏。整个生成过程必须严格按照工具调用格式与步骤执行,确保生成的代码既安全又高效。
Gemini 生成代码示例
{
"contents":
[
{
"parts":
[
{
"text": "请根据下面的用户的问题和答案使用python代码绘制函数图像帮助用户更好的理解问题.如果无需绘制函数图像,请返回`not_needed`"
},
{
"text": "解题"
},
{
"text": "已知函数 \\( f(x) = x^2 \\),求其在某一点 \\( x = a \\) 处的切线方程。\r\n\r\n### **步骤**\r\n1. **求导数** \r\n 函数的导数表示其变化率,即:\r\n \\[\r\n f'(x) = \\frac{d}{dx} (x^2) = 2x\r\n \\]\r\n 这表示函数在任意点 \\( x \\) 处的瞬时变化率(斜率)。\r\n\r\n2. **计算切线的斜率** \r\n 在 \\( x = a \\) 处,切线的斜率为:\r\n \\[\r\n m = f'(a) = 2a\r\n \\]\r\n\r\n3. **确定切点** \r\n 切线经过的点为 \\( (a, f(a)) \\),即:\r\n \\[\r\n (a, a^2)\r\n \\]\r\n\r\n4. **写出切线方程** \r\n 直线方程的点斜式为:\r\n \\[\r\n y - y_1 = m (x - x_1)\r\n \\]\r\n 代入 \\( (a, a^2) \\) 和 \\( m = 2a \\):\r\n \\[\r\n y - a^2 = 2a (x - a)\r\n \\]\r\n 展开整理:\r\n \\[\r\n y = 2a x - a^2\r\n \\]\r\n\r\n### **结论**\r\n函数 \\( f(x) = x^2 \\) 在 \\( x = a \\) 处的切线方程为:\r\n\\[\r\ny = 2a x - a^2\r\n\\]\r\n\r\n如果你有具体的 \\( a \\) 值,我可以帮你计算出具体的切线方程。"
}
],
"role": "user"
}
],
"system_instruction":
{
"parts":
{
"text": "你是 Cline,一位技术高超的软件工程师,精通 Python 编程、各种框架、设计模式以及最佳实践。你的任务是根据用户需求生成符合规范、易于维护的 Python 代码。请务必遵循以下要求和步骤:\r\n\r\n1. 代码风格要求:\r\n- 所有 Python 代码必须符合 PEP8 标准,结构清晰,注释充分,必要时提供文档字符串说明。\r\n- 代码中的变量、函数、类等命名必须有意义,且遵循 Python 命名规范。\r\n\r\n2. 工具调用要求:\r\n- 当需要创建新文件、编辑文件或执行命令时,必须使用指定的工具,且调用格式严格按照 XML 标签格式书写。例如:\r\n- 使用 `execute_python` 工具执行 python.\r\n- 每次调用工具后,必须等待用户确认工具使用成功后再进行下一步操作,不得跳步或假设成功。\r\n\r\n3. 文件操作要求:\r\n- 生成的文件路径均以当前工作目录(.)为基准。\r\n- 如果需要生成 Python 脚本或模块,务必确保文件的完整内容不遗漏,并在必要时提供完整的代码示例。\r\n\r\n4. 任务执行流程:\r\n- 首先分析用户需求,确定是否需要执行代码。如果不需要执行代码,设置action为 not_needed\r\n- 如果需要执行,确定生成代码所需的功能模块、函数、类等结构。\r\n- 如果代码生成过程中需要调用外部 API 或系统命令,请确保命令安全、格式正确,并在调用前提供详细说明。\r\n- 生成代码后,确保代码能够正确运行并完成预期功能。\r\n\r\n5. 代码生成要求\r\n- 所有包含数学公式(mathtext)的字符串必须使用原始字符串前缀 `r''`,以防止转义字符错误。\r\n- 在 mathtext 表达式中,LaTeX 命令必须使用 **单斜杠** `\\`,不要使用双斜杠 `\\\\`,否则会导致 matplotlib 渲染失败。\r\n- 正确示例:\r\n plt.plot(x, y, label=r'$f(x) = \\frac{2}{3}\\sqrt{x^3 + 1}$')\r\n plt.title(r'Plot of $f(x) = \\frac{2}{3}\\sqrt{x^3 + 1}$')\r\n \r\n- 错误示例:\r\n plt.plot(x, y, label=r'$f(x) = \\frac{2}{3}\\\\sqrt{x^3 + 1}$') # 错误:用了双斜杠\r\n plt.title('Plot of $f(x) = \\frac{2}{3}\\sqrt{x^3 + 1}$') # 错误:缺少 r''\r\n \r\n - 若使用 matplotlib 的 mathtext 功能,必须确保表达式在 `$...$` 内闭合且无语法错误。\r\n\r\n6. 示例说明:\r\n- 以下为创建一个简单 Python 脚本的示例,该脚本实现打印 \"Hello, world!\" 的功能:\r\n\r\n```python\r\nprint(\"Hello, world!\")\r\n```\r\n\r\n- 下面给出一个示例 Python 脚本,演示如何绘制函数图形和其切线:\r\n\r\n```python\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\n\r\n# 定义函数 f(x) = x^2\r\ndef f(x):\r\n return x**2\r\n\r\n# 定义切线方程\r\ndef tangent_line(a, x):\r\n return 2*a*x - a**2\r\n\r\n# 生成 x 数据\r\nx = np.linspace(-5, 5, 400)\r\ny = f(x)\r\n\r\n# 选取多个切点\r\na_values = [-2, -1, 0, 1, 2]\r\n\r\n# 绘图\r\nplt.figure(figsize=(8, 6))\r\nplt.plot(x, y, label=r'$f(x) = x^2$', color='blue')\r\n\r\n# 绘制每个切点的切线\r\nfor a in a_values:\r\n tangent_y = tangent_line(a, x)\r\n plt.plot(x, tangent_y, '--', label=fr'Tangent at $x={a}$')\r\n\r\n # 标记切点\r\n plt.scatter(a, f(a), color='red', zorder=3)\r\n\r\n# 设置图表属性\r\nplt.xlabel('x')\r\nplt.ylabel('y')\r\nplt.title('Function $f(x) = x^2$ and its Tangents')\r\nplt.axhline(0, color='black', linewidth=0.5)\r\nplt.axvline(0, color='black', linewidth=0.5)\r\nplt.legend()\r\nplt.grid(True)\r\n\r\n# 显示图形\r\nplt.show()\r\n```\r\n请根据以上所有提示和用户要求,生成符合用户需求的 Python 代码,并确保所有细节都不遗漏。整个生成过程必须严格按照工具调用格式与步骤执行,确保生成的代码既安全又高效。"
}
},
"generationConfig":
{
"responseSchema":
{
"properties":
{
"code":
{
"type": "string"
},
"action":
{
"type": "string"
},
"tool":
{
"type": "string"
}
},
"type": "object"
},
"topK": 40,
"topP": 0.95,
"temperature": 1.0,
"maxOutputTokens": 8192,
"responseMimeType": "application/json"
}
}
output
{
"action": "not_needed"
}
{
"action": "code_needed",
"code": "import numpy as np\nimport matplotlib.pyplot as plt\n\n# 定义函数 f(x) = x^2\ndef f(x):\n return x**2\n\n# 定义切线方程\ndef tangent_line(a, x):\n return 2*a*x - a**2\n\n# 生成 x 数据\nx = np.linspace(-5, 5, 400)\ny = f(x)\n\n# 选取多个切点\na_values = [-2, -1, 0, 1, 2]\n\n# 绘图\nplt.figure(figsize=(8, 6))\nplt.plot(x, y, label=r'$f(x) = x^2$', color='blue')\n\n# 绘制每个切点的切线\nfor a in a_values:\n tangent_y = tangent_line(a, x)\n plt.plot(x, tangent_y, '--', label=fr'Tangent at $x={a}$')\n\n # 标记切点\n plt.scatter(a, f(a), color='red', zorder=3)\n\n# 设置图表属性\nplt.xlabel('x')\nplt.ylabel('y')\nplt.title('Function $f(x) = x^2$ and its Tangents')\nplt.axhline(0, color='black', linewidth=0.5)\nplt.axvline(0, color='black', linewidth=0.5)\nplt.legend()\nplt.grid(True)\n\n# 显示图形\nplt.show()",
"tool": "execute_python"
}
2. Java 服务端实现
为了确保生成的 Python 代码能够正确运行,本系统将 Python 代码发送到 java-linux-server 上执行。以下介绍三个关键模块的代码实现:
2.1 GeminiResponseSchema
package com.litongjava.gemini;
import java.util.HashMap;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GeminiResponseSchema {
private String type = "object";
private Map<String, GeminiResponseProperty> properties;
/**
"responseSchema": {
"type": "object",
"properties": {
"suggestions": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
*/
public static GeminiResponseSchema array(String key) {
Map<String, String> items = itemType("string");
Map<String, GeminiResponseProperty> properties = new HashMap<>();
properties.put(key, new GeminiResponseProperty("array", items));
GeminiResponseSchema schema = new GeminiResponseSchema();
schema.setProperties(properties);
return schema;
}
/**
*
"responseSchema": {
"type": "object",
"properties": {
"action": {
"type": "string"
},
"tool": {
"type": "string"
}
"code": {
"type": "string"
},
}
}
* @return
*/
public static GeminiResponseSchema pythonCode() {
Map<String, GeminiResponseProperty> properties = new HashMap<>();
properties.put("action", new GeminiResponseProperty("string"));
properties.put("tool", new GeminiResponseProperty("string"));
properties.put("code", new GeminiResponseProperty("string"));
GeminiResponseSchema schema = new GeminiResponseSchema();
schema.setProperties(properties);
return schema;
}
private static Map<String, String> itemType(String value) {
Map<String, String> items = new HashMap<>();
items.put("type", value);
return items;
}
}
2.2 MatplotlibService
MatplotlibService
类负责调用大模型生成 Python 代码,并对返回的结果进行处理。具体步骤如下:
- 生成代码:调用
generateCode
方法,将用户的需求与系统提示词结合后生成 Python 代码。 - 解析 XML:检查生成的代码中是否包含
<execute_python>
标签,若存在,则利用工具类解析出其中的 Python 代码。 - 执行代码:通过
LinuxClient.executePythonCode
方法将 Python 代码发送给 java-linux-server 执行,并处理可能的错误信息。 - 错误处理:若代码执行过程中出现错误,会根据错误信息调用
fixCodeError
方法进行修正后重新执行代码。 - 图像上传:当 Python 代码执行生成图像时,对生成的 Base64 图片进行解码,并上传到 AWS S3,最终返回图片 URL。
完整代码如下:
package com.litongjava.llm.service;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import com.litongjava.gemini.GeminiCandidateVo;
import com.litongjava.gemini.GeminiChatRequestVo;
import com.litongjava.gemini.GeminiChatResponseVo;
import com.litongjava.gemini.GeminiClient;
import com.litongjava.gemini.GeminiGenerationConfigVo;
import com.litongjava.gemini.GeminiPartVo;
import com.litongjava.gemini.GeminiResponseSchema;
import com.litongjava.gemini.GoogleGeminiModels;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.linux.LinuxClient;
import com.litongjava.linux.ProcessResult;
import com.litongjava.llm.vo.ToolVo;
import com.litongjava.template.PromptEngine;
import com.litongjava.tio.boot.admin.services.AwsS3StorageService;
import com.litongjava.tio.boot.admin.vo.UploadResultVo;
import com.litongjava.tio.http.common.UploadFile;
import com.litongjava.tio.utils.encoder.Base64Utils;
import com.litongjava.tio.utils.encoder.ImageVo;
import com.litongjava.tio.utils.hutool.StrUtil;
import com.litongjava.tio.utils.json.JsonUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MatplotlibService {
public ProcessResult generateMatplot(String quesiton, String answer) {
String text = generateCode(quesiton, answer);
if (StrUtil.isBlank(text)) {
return null;
}
ToolVo toolVo = null;
try {
toolVo = JsonUtils.parse(text, ToolVo.class);
} catch (Exception e) {
log.error("text:{}", text, e.getMessage(), e);
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
String stackTrace = stringWriter.toString();
String msg = "code:" + text + ",stackTrace" + stackTrace;
Aop.get(AgentNotificationService.class).sendError(msg);
return null;
}
if (toolVo != null && "execute_python".equals(toolVo.getTool())) {
String code = toolVo.getCode();
ProcessResult result = LinuxClient.executePythonCode(code);
if (result != null) {
String stdErr = result.getStdErr();
if (StrUtil.isNotBlank(stdErr)) {
String prompt = "python代码执行过程中出现了错误,请修正错误并仅输出修改后的代码,错误信息:%s";
prompt = String.format(prompt, stdErr);
code = fixCodeError(prompt, code);
result = LinuxClient.executePythonCode(code);
}
List<String> images = result.getImages();
if (images != null) {
List<String> imageUrls = new ArrayList<>(images.size());
for (String imageBase64Code : images) {
ImageVo decodeImage = Base64Utils.decodeImage(imageBase64Code);
UploadFile uploadFile = new UploadFile("matplotlib." + decodeImage.getExtension(), decodeImage.getData());
UploadResultVo resultVo = Aop.get(AwsS3StorageService.class).uploadFile("matplotlib", uploadFile);
String url = resultVo.getUrl();
imageUrls.add(url);
}
result.setImages(imageUrls);
}
return result;
}
}
return null;
}
private String fixCodeError(String userPrompt, String code) {
String text = generateCode(userPrompt, code);
if (StrUtil.isBlank(text)) {
return null;
}
ToolVo toolVo = null;
try {
toolVo = JsonUtils.parse(text, ToolVo.class);
return toolVo.getCode();
} catch (Exception e) {
log.error("text:{}", text, e.getMessage(), e);
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
String stackTrace = stringWriter.toString();
String msg = "code:" + text + ",stackTrace" + stackTrace;
Aop.get(AgentNotificationService.class).sendError(msg);
return null;
}
}
public String generateCode(String quesiton, String answer) {
String systemPrompt = PromptEngine.renderToString("python_code_prompt.txt");
String userPrompt = "请根据下面的用户的问题和答案使用python代码绘制函数图像帮助用户更好的理解问题.如果无需绘制函数图像,请返回`not_needed`";
// 1. Construct request body
GeminiChatRequestVo reqVo = new GeminiChatRequestVo();
reqVo.setUserPrompts(userPrompt, quesiton, answer);
reqVo.setSystemPrompt(systemPrompt);
GeminiResponseSchema pythonCode = GeminiResponseSchema.pythonCode();
GeminiGenerationConfigVo geminiGenerationConfigVo = new GeminiGenerationConfigVo();
geminiGenerationConfigVo.buildJsonValue().setResponseSchema(pythonCode);
reqVo.setGenerationConfig(geminiGenerationConfigVo);
// 2. Send sync request: generateContent
GeminiChatResponseVo respVo = GeminiClient.generate(GoogleGeminiModels.GEMINI_2_0_FLASH, reqVo);
if (respVo != null) {
List<GeminiCandidateVo> candidates = respVo.getCandidates();
GeminiCandidateVo candidate = candidates.get(0);
List<GeminiPartVo> parts = candidate.getContent().getParts();
if (candidate != null && candidate.getContent() != null && parts != null) {
String text = parts.get(0).getText();
return text;
}
}
return null;
}
}
2.3 LinuxClient
LinuxClient
类负责与 java-linux-server 进行交互,通过 HTTP 请求将生成的 Python 代码提交至后端执行,并接收执行结果。其主要步骤包括:
- 根据环境变量构造 API 请求地址和验证 key;
- 构造 HTTP 请求,将 Python 代码作为 POST 请求的内容发送至服务器;
- 解析服务器返回的 JSON 数据,并将其转换为
ProcessResult
对象返回给上层调用。
完整代码如下:
package com.litongjava.linux;
import java.io.IOException;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.litongjava.tio.utils.http.OkHttpClientPool;
import com.litongjava.tio.utils.json.JsonUtils;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class LinuxClient {
public static ProcessResult executePythonCode(String code) {
String apiBase = EnvUtils.getStr("LINUX_BASE_URL");
String key = EnvUtils.getStr("LINUX_API_KEY");
String arg0 = apiBase + "/python";
MediaType mediaType = MediaType.parse("text/plain");
OkHttpClient client = OkHttpClientPool.get60HttpClient();
RequestBody body = RequestBody.create(code, mediaType);
Request request = new Request.Builder().url(arg0).method("POST", body).addHeader("authorization", "Bearer " + key).build();
Call call = client.newCall(request);
try (Response response = call.execute()) {
String string = response.body().string();
int resposneCode = response.code();
if (response.isSuccessful()) {
return JsonUtils.parse(string, ProcessResult.class);
} else {
throw new RuntimeException("code:" + resposneCode + " response:" + string);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
2.4 测试类
package llm;
import java.net.URL;
import org.junit.Test;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.linux.ProcessResult;
import com.litongjava.llm.service.MatplotlibService;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.litongjava.tio.utils.hutool.FileUtil;
import com.litongjava.tio.utils.hutool.ResourceUtil;
public class MatplotlibServiceTest {
@Test
public void test() {
EnvUtils.load();
URL resource = ResourceUtil.getResource("data/example_answer.txt");
if (resource == null) {
return;
}
StringBuilder readURLAsString = FileUtil.readURLAsString(resource);
String generateCode = Aop.get(MatplotlibService.class).generateCode("解题",readURLAsString.toString());
// String generateCode = Aop.get(MatplotlibService.class).generateCode("解题","我爱你");
System.out.println(generateCode);
}
@Test
public void generateMatplot() {
EnvUtils.load();
URL resource = ResourceUtil.getResource("data/example_answer.txt");
if (resource == null) {
return;
}
StringBuilder readURLAsString = FileUtil.readURLAsString(resource);
for (int i = 0; i < 10; i++) {
try {
ProcessResult generateMatplot = Aop.get(MatplotlibService.class).generateMatplot("解题", readURLAsString.toString());
System.out.println(generateMatplot);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3. 说明与接收
代码生成与调用流程说明
- 用户需求由大模型接收,结合
python_code_prompt.txt
的系统提示词生成符合要求的 Python 代码。 - 生成的代码通过 XML 格式封装在
<execute_python>
标签内。 MatplotlibService
类从返回的 XML 中提取出 Python 代码,并调用LinuxClient.executePythonCode
将代码发送至后端执行。- 若执行过程中发现错误,系统会调用
fixCodeError
方法,通过大模型进行错误修正后重新执行。 - 如果生成了图像,系统还会进行图像上传,并返回图像的 URL。
- 用户需求由大模型接收,结合
安全性与可维护性
- 所有生成的代码均严格遵守 PEP8 规范,变量、函数和类命名明确。
- 使用原始字符串(
r''
)保证数学公式在 matplotlib 渲染时不会出现转义错误。 - Java 服务端通过环境变量配置后端 API 地址和安全密钥,确保请求安全。
接收与反馈
- 请在实际使用过程中确认每一步工具调用成功后,再进行下一步操作。
- 若在 Python 代码执行过程中出现错误,请及时根据错误信息修正代码,并通过系统提示反馈给开发团队进行处理。