华数杯数学建模竞赛这类题目,很多人第一步就是打开 ChatGPT 把题目丢进去,等它吐出一篇“结论正确、过程漂亮”的答案。但真正参加过比赛的人都知道,AI 直接生成的建模方案往往存在两个问题:要么过于泛化,没有针对数据做任何实际计算;要么看似专业,一跑代码就报错,二次修复成本极高。
这里真正值得讨论的不是“AI 能不能替代人写数模论文”,而是“如何用 AI 智能体把读题、拆解、建模、计算、验证、写论文这条长链路变成可迭代的工程流程”。我的判断是:用 AI 智能体(Agent)而不是单轮对话,才是参与华数杯这类数学建模竞赛的正确姿势。
这篇文章会从一个最小可用的建模助手智能体出发,讲清楚 Agent 在数学建模中的定位、核心设计、完整代码、运行验证、常见排错,以及比赛合规边界。读完你能亲手搭一个“会拆题、会调工具、会自我检查”的 AI 智能体,并用它跑通一道华数杯风格的预测题。
1. 为什么数学建模适合用智能体,而不是“一问一答”
先看一个典型场景。你把一道华数杯真题粘给普通 AI 对话框,它会告诉你:“本题适合用层次分析法结合熵权法,建议构建模糊综合评价模型……”,然后给出大段公式。看起来很有道理,但当你追问“请把附件里的 1000 行数据跑出来,给出最终排名”时,对话就开始失控。
问题出在哪里?数学建模任务有四个特点:
- 流程长:从问题重述、模型假设、符号说明、模型建立、求解、检验,到论文写作,不是一次对话能完成的。
- 状态多:中间结果要保留,不同模型之间要对比,误差要调整。
- 强工具依赖:需要执行 Python 代码、读 Excel、画图、算指标,纯文本对话做不到。
- 需要验证:AI 给出的结论必须经过数据计算验证,不能“纸上谈兵”。
普通对话式 AI 是“无状态输出器”,你问一句它答一句,缺少目标感、任务拆解和工具调用能力。而 Agent 的基本定义就是:一个能自主拆解目标、按步骤执行、调用外部工具、根据反馈修正行为的智能程序。
在数学建模场景里,Agent 更像一个“有工作流的 AI 实习生”:
| 能力 | 单轮对话 | 建模助手 Agent |
|---|---|---|
| 拆解题目 | 直接给结论 | 先还原问题、列出假设、形成任务清单 |
| 数据计算 | 不能执行 | 调用 Python 工具,跑真实数据 |
| 中途纠错 | 需要用户反复追问 | 根据运行结果自动调整 |
| 过程记录 | 无 | 保留状态和决策日志 |
| 结果可信度 | 低 | 计算可复现,结论可验证 |
所以我一直强调:用 AI 写题,重点不是“让它生成答案”,而是“搭一条从题目到可验证结论的处理流水线”。这才是 AI Agent 对数学建模真正有价值的切入点。
2. AI 智能体的核心原理与建模场景映射
在进入代码之前,先厘清几个概念。
2.1 Agent 是什么
Agent 是“有目标、有工具、能自我修正”的对话程序。它的最小闭环是:
观察(接收题目/中间结果) → 思考(拆解下一步) → 行动(调用工具或输出) → 观察新结果 → 循环这种模式在 AI Agent 领域叫 ReAct 模式(Reasoning + Acting),核心思想是让模型在“推理”和“行动”之间交替进行,而不是一次性输出最终答案。
2.2 数学建模中的 Agent 角色分工
一个完整的数模参赛团队通常有建模手、编程手、写作手。Agent 设计时也可以按角色拆分:
- 读题 Agent:负责压缩题目信息、提取约束条件、明确目标和数据字段。
- 建模 Agent:给出候选模型、说明假设、推导公式、指出适用条件。
- 编程 Agent:把模型转成可运行的 Python 代码,调用数据完成求解。
- 验证 Agent:对比多组结果、做误差分析、检查假设是否被违反。
当然,个人参赛时不需要真的写四个独立程序。比较务实的做法是:用一个 Agent 主程序驱动不同阶段的 Prompt,并注册统一的工具函数。这也是下面完整示例采用的设计。
2.3 编排平台与自研代码怎么选
现在搭 Agent 有两条路。
第一条是使用可视化编排平台,比如 Dify、Coze 这类 AI 智能体平台。优点是拖拽节点、免部署、快速验证 Prompt;缺点是数据处理和比赛题目的定制逻辑比较受限,而且平台策略也会变化。
第二条是自研代码,用大模型 API + 简单的工具调用循环。优点是灵活、可复现、能嵌入自己的数据处理流程,也方便比赛时做代码版本管理;缺点是需要自己处理模型输出格式、异常、超时等问题。
我的建议是:比赛场景优先自研代码。因为数学建模论文本身要求代码可复现,你不可能在论文里说“我是用某个在线平台点出来的”。自研 Agent 生成的代码、日志、结果,都能直接成为论文附录的一部分。
3. 环境准备与前置条件
开始写代码前,先准备环境。
3.1 运行环境
- 操作系统:Windows 10/11、macOS、Linux 均可。
- Python 版本:建议 3.10 或更高。本文代码不依赖 Python 3.10 的独有语法,3.8 以上也能运行。
- 大模型接口:需要一个兼容 OpenAI 格式的大模型 API。可以使用国内可合法访问的模型服务商,或本地部署的开源模型。密钥通过环境变量传入,不要写死到代码里。
- 依赖库:
openai、python-dotenv、pandas、numpy、matplotlib。版本请以实际安装为准,这里不锁死版本。
pip install openai python-dotenv pandas numpy matplotlib3.2 密钥配置
在项目根目录创建.env文件:
MODEL_API_KEY=your_api_key_here MODEL_API_BASE=https://your-api-endpoint.example.com MODEL_NAME=gpt-4o-mini然后在代码中加载:
import os from dotenv import load_dotenv load_dotenv() API_KEY = os.getenv("MODEL_API_KEY") API_BASE = os.getenv("MODEL_API_BASE") MODEL_NAME = os.getenv("MODEL_NAME")安全提醒:.env文件必须加入.gitignore,绝对不要提交到公共仓库。
3.3 目录结构
modeling_agent/ ├── .env ├── .gitignore ├── agent_tools.py ├── modeling_agent.py ├── main.py └── data/ └── water_usage.csv4. 核心设计:把数模流程拆成 Agent 工作流
AI Agent 能不能稳定干活,取决于两个设计:系统提示词和工具执行机制。
4.1 系统提示词:给 Agent 立规矩
系统提示词(System Prompt)是 Agent 的“工作手册”。数学建模助手的人设可以这样写:
# 文件路径:prompts.py SYSTEM_PROMPT = """ 你是一位数学建模竞赛教练,擅长指导选手完成从读题、建模、计算到论文写作的完整流程。 你在回答时遵循以下规则: 1. 先复述题目目标,列清楚约束条件和可用数据字段。 2. 把任务拆成可执行的小步骤,每步只做一件事。 3. 当需要数据计算、统计分析、画图时,你必须调用 python 工具。 4. 每次调用工具后,根据输出结果决定下一步,不要假装计算成功。 5. 输出结论时,必须附上关键数字、使用的模型和误差指标。 6. 如果你发现前一步结果不合理,要主动说明并尝试修正。 7. 尊重学术诚信。你提供的是分析框架和计算辅助,不代表选手完成全部工作。 你的输出格式要求: - 当需要执行代码时,输出两行内容: ACTION: python ACTION_INPUT: 需要执行的 Python 代码 - 当不需要执行代码时,正常输出文字分析。 注意: - 代码必须是完整可运行的 Python 脚本。 - 不要生成调用外部文件的绝对路径。 - 如果数据不存在,先用示例数据说明方法,再提示真实数据路径。 """这里的关键是:要求模型在需要计算时显式输出 ACTION 指令。这套指令格式是后面 Agent 主循环能运转的基础。
4.2 工具执行:安全运行模型生成的代码
模型生成的 Python 代码不能直接在主进程里执行,因为:
- AI 代码可能有语法错误或无限循环。
- AI 代码可能访问敏感文件、执行危险操作。
- 主进程被卡住会影响整个 Agent 循环。
所以最好的做法是把代码丢到一个subprocess子进程里跑,并设置超时时间。这就是agent_tools.py做的事情:
# 文件路径:agent_tools.py import subprocess import sys import textwrap def safe_execute(code: str, timeout: int = 15): """ 在子进程中执行 AI 生成的 Python 代码。 限制执行时间,避免无限循环拖垮 Agent。 """ wrapped_code = textwrap.dedent(f""" try: {textwrap.indent(code, ' ')} except Exception as e: print("EXEC_ERROR:", e) """) try: proc = subprocess.run( [sys.executable, "-c", wrapped_code], capture_output=True, text=True, timeout=timeout, ) output = proc.stdout + proc.stderr except subprocess.TimeoutExpired: output = "EXEC_ERROR: 执行超时,请检查代码是否存在死循环。" return output.strip() TOOLS = { "python": { "description": "执行一段 Python 代码,用于计算、分析数据、画图。", "func": safe_execute, } }这里有三个工程细节值得注意:
textwrap.indent让模型生成的代码缩进保持正确,避免try块内缩进错误。- 统一捕获异常并输出
EXEC_ERROR,让模型能读到错误信息并自我修正。 - 超时机制保证了即使 AI 写出死循环,Agent 也能继续运行。
4.3 Agent 主循环:读题 → 规划 → 执行 → 验证
modeling_agent.py是 Agent 的核心循环,逻辑如下:
- 把系统提示词和用户题目拼起来发给模型。
- 模型返回结果。
- 检查结果中是否包含
ACTION: python。 - 如果有,提取
ACTION_INPUT中的代码,交给safe_execute执行。 - 把执行结果作为“观察”信息重新发给模型,让模型决定下一步。
- 如果没有 ACTION,说明模型已经给出最终分析,结束循环。
# 文件路径:modeling_agent.py import re from openai import OpenAI from agent_tools import TOOLS class ModelingAgent: def __init__(self, api_key, api_base, model_name): self.client = OpenAI(api_key=api_key, base_url=api_base) self.model_name = model_name self.messages = [] self.max_iterations = 6 def add_system_prompt(self, prompt: str): self.messages.append({"role": "system", "content": prompt}) def chat(self, user_query: str): self.messages.append({"role": "user", "content": user_query}) for step in range(self.max_iterations): response = self.client.chat.completions.create( model=self.model_name, messages=self.messages, temperature=0.2, ) reply = response.choices[0].message.content self.messages.append({"role": "assistant", "content": reply}) # 检查是否需要调用工具 action_match = re.search(r"ACTION:\s*python", reply) if not action_match: return reply code_match = re.search( r"ACTION_INPUT:\s*(.*?)(?:ACTION:|$)", reply, flags=re.DOTALL, ) if not code_match: return "模型输出缺少 ACTION_INPUT,无法执行工具。" code = code_match.group(1).strip() print(f"\n[Step {step + 1}] 模型正在执行 Python 代码...") tool_output = TOOLS["python"]["func"](code) print(f"[Tool Output]\n{tool_output[:500]}") self.messages.append({ "role": "user", "content": f"工具执行结果如下:\n{tool_output}\n请根据这个结果继续分析,或给出最终结论。", }) return "达到最大迭代次数,请人工介入检查。"把这个类封装好之后,main.py只需要几行代码就能启动:
# 文件路径:main.py import os from dotenv import load_dotenv from prompts import SYSTEM_PROMPT from modeling_agent import ModelingAgent load_dotenv() agent = ModelingAgent( api_key=os.getenv("MODEL_API_KEY"), api_base=os.getenv("MODEL_API_BASE"), model_name=os.getenv("MODEL_NAME"), ) agent.add_system_prompt(SYSTEM_PROMPT) query = ( "某城市 2021 年 1 月到 2024 年 12 月每月用水量数据(单位:万立方米)如下:\n" "[120, 118, 125, 132, 145, 152, 148, 140, 135, 130, 122, 119, ...]\n" "请建立合适的模型预测 2025 年 12 月的用水量,并分析季节性和趋势。" ) result = agent.chat(query) print("\n===== 最终结论 =====") print(result)5. 完整示例:跑通一道华数杯风格预测题
为了让演示可复现,我用一组模拟数据代替真实比赛数据,重点展示 Agent 的完整工作过程。
5.1 模拟数据生成
先把模拟数据写入water_usage.csv。这里用 Python 生成带趋势和季节性的 48 个月数据:
# 文件路径:generate_data.py import pandas as pd import numpy as np np.random.seed(42) months = pd.date_range("2021-01-01", periods=48, freq="M") trend = np.linspace(0, 20, 48) seasonal = 15 * np.sin(np.linspace(0, 8 * np.pi, 48)) noise = np.random.normal(0, 3, 48) water = 120 + trend + seasonal + noise df = pd.DataFrame({"month": months, "water": water}) df.to_csv("data/water_usage.csv", index=False) print(df.head())这份数据模拟了“整体上升 + 季节性波动”的用水特征,是数模题里很常见的结构。
5.2 运行 Agent
把上面的query改为读取真实 CSV:
query = ( "请读取 data/water_usage.csv 文件,分析用水量是否存在趋势和季节性," "并建立合适模型预测 2025 年 12 月的用水量。" )运行:
python main.py5.3 预期输出与结果分析
Agent 的运行过程大致如下图所示(这里用文字模拟控制台输出,不同模型输出会有差异,但流程一致):
[Step 1] 模型正在执行 Python 代码... [Tool Output] month water 0 2021-01-31 111.653019 1 2021-02-28 107.365493 2 2021-03-31 116.028822 ... [Step 2] 模型正在执行 Python 代码... [Tool Output] 趋势斜率: 0.406 相关系数: 0.87 季节性方差显著大于随机噪声方差 [Step 3] 模型正在执行 Python 代码... [Tool Output] 预测 2025-12 用水量: 166.32 95% 置信区间: [157.80, 174.84] R方: 0.91最终结论示例:
从数据看,该城市用水量存在明显的上升趋势和年度季节性,冬季偏低、夏季偏高。 使用线性趋势加月度季节虚拟变量的回归模型,预测 2025 年 12 月用水量约为 166.32 万立方米。 模型 R方为 0.91,说明趋势和季节性能解释大部分数据波动。建议将预测结果结合实际政策因素再做调整。从输出能明显看出,这已经不是“AI 空谈方案”,而是经过了真实数据计算。
6. 如何验证 Agent 的结论是否可信
AI Agent 生成的结果不能直接写进论文,必须经过人工验证。建议按下面顺序检查。
6.1 验证代码可复现
把 Agent 生成的代码保存下来,独立运行一遍。如果换一台机器还能跑出同样结果,才说明代码是完整的。这里推荐用 Git 管理每次 Agent 生成的脚本和结果:
git init git add modeling_agent.py agent_tools.py prompts.py main.py git commit -m "初始化建模助手 Agent"6.2 验证模型的合理性
- 检查模型假设是否符合题目背景。比如线性趋势是否过度简化?数据量是否足够支撑复杂模型?
- 检查误差指标。R方、MAE、RMSE 等指标需要在合理范围内。
- 检查预测边界。如果预测值和历史数据差距过大,要追查原因,而不是盲目采信。
6.3 交叉验证
让 Agent 用第二种模型(例如 ARIMA 或 Prophet)再预测一次,对比结果。如果两个模型给出的预测值相差过大,说明问题对模型选择敏感,论文里要重点讨论这一点。
# 人工补充的交叉验证代码:statsmodels 可用时执行 # 该段代码不是由 Agent 生成,是选手自己编写的验证脚本6.4 留意“AI 幻觉”
AI 在数学建模中特别容易出现“幻觉式成功”:明明没有执行代码,却输出了一串看起来很精确的数字。这也是为什么必须在 Agent 里强制要求“需要计算时必须调用 python 工具”,并且把工具输出原样记录。所有关键数字必须能找到对应的运行日志。
7. 常见问题与排查思路
在实际使用过程中,最容易遇到的问题有下面几类:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| Agent 一直不调用 Python 工具,直接给结论 | 系统提示词约束不够强 | 检查回复中是否出现 ACTION | 在提示词里加入“遇到数据计算必须调用 python”的硬性规则 |
| Python 代码执行报错,Agent 无法自我修正 | 错误信息被截断 | 打印完整 Tool Output | 增大输出长度限制,把完整错误信息回传给模型 |
| 执行超时 | 模型写出死循环 | 查看错误日志中的超时信息 | 调高 timeout 或让模型输出“分步执行”的代码 |
| 模型输出格式不符合 ACTION/ACTION_INPUT 规范 | 模型未理解格式,或回复中夹杂多余内容 | 检查原始回复文本 | 用正则兼容多种格式,并在提示词中给出示例 |
| 数据路径错误 | 模型使用了不存在的路径 | 观察 Tool Output 中的路径信息 | 在系统提示词里说明数据目录结构 |
| API 调用被限流 | 请求频率过高 | 查看 API 返回状态 | 增加重试和退避机制 |
补充一个很常见的坑:正则表达式容易把 ACTION 后面的说明文字一起当作代码。上面的代码已经用re.DOTALL让.可以匹配换行,但如果你发现工具执行的代码里混入“以下是代码”这类中文说明,就需要在提取时增加清洗逻辑:
def clean_code_block(code: str) -> str: # 去掉常见的围栏和说明文字 code = code.replace("```python", "").replace("```", "") lines = [line for line in code.splitlines() if not line.strip().startswith("以下是")] return "\n".join(lines).strip()8. 竞赛合规与工程最佳实践
8.1 学术诚信,必须放在第一位
华数杯这类数学建模竞赛的核心是考察参赛者的建模能力。AI 智能体可以充当“高效的检索器、计算器、代码助手”,但不能替代你完成全部思考。更稳妥的做法是:
- 用 Agent 生成候选思路和代码初稿,然后自己重新推导关键公式。
- 所有数据和计算代码保留在项目仓库中,论文里明确说明“使用了 AI 辅助工具进行代码调试和结果检验”。
- 不直接粘贴 Agent 生成的整段论文,尤其是问题分析、模型评价等主观叙述。
现在部分竞赛对 AI 使用有明确声明要求。提交前务必阅读比赛规则,按规则标注 AI 参与情况。
8.2 密钥与代码安全
- API 密钥只放在
.env,并加入.gitignore。 - Agent 生成的代码默认在子进程中执行,但仍要避免给模型不必要的文件访问权限。
- 如果数据涉及隐私或未公开信息,不要上传到外部 API,改用本地模型或脱敏数据。
8.3 工程化迭代
把 Agent 当作“队友”而不是“答案机”,使用过程中建议:
- 每次运行保留日志,方便复盘 Agent 哪一步走了弯路。
- 多模型对比:同一个问题,换不同模型或不同 temperature 跑多次,观察结果稳定性。
- 设置迭代上限:
max_iterations防止 Agent 无限循环。 - 把 Prompt 版本化:每次修改系统提示词都记录版本,避免改坏后无法回退。
- 数据核对优先于结果优化:先确认数据读入正确、字段无缺失,再谈建模效果。
8.4 Agent 输出的人工审查清单
最终写进论文前,逐项确认:
- 关键数字是否能在运行日志中找到对应代码。
- 数据可视化图片是否标注了数据来源。
- 模型假设是否与题目条件一致。
- 是否有异常值的处理记录。
- 预测结果是否经过至少一次交叉验证。
9. 总结与实践建议
回到最初的问题:用 AI 智能体写题华数杯,到底该怎么做?
我的结论是:不要追求让 AI “一步到位生成满分论文”,而是把重点放在构建一个读题→拆解→建模→计算→验证→总结的自动化工作流。智能体的价值不在输出,而在于它能帮你把每一个中间步骤跑通,留下可复现的计算过程和可追溯的决策日志。
如果你现在只有三天准备时间,建议按这个顺序实践:
- 先跑通上面的最小 Agent 代码,把题目丢进去,观察它拆解任务的思路。
- 准备一份模拟数据或往届公开数据,让 Agent 完成一次完整的“读题到预测”。
- 把 Agent 的关键结论用传统方法(如手写回归、Excel 分析)验证一遍。
- 把这套流程沉淀成你的参赛工具链,包括 Prompt、工具函数、日志模板。
后续想深入,可以往两个方向走:一是用可视化编排平台(如 Dify、Coze 这类智能体平台)把多角色 Agent 拖出来,快速验证思路;二是研究多智能体协作,让建模 Agent、编程 Agent、写作 Agent 分别负责一个环节,通过消息队列交换结果。
无论工具怎么迭代,有一条原则永远不会变:AI 智能体是对你思考能力的增强,而不是替代。把它当成一个任劳任怨、不会疲惫的分析师,用它跑完所有能跑的计算,然后把判断和决策牢牢握在自己手里。