最近,我跟团队落地了一个基于 Python 的 AI Web 应用项目,终于让我体会到,大模型与实际业务融合远比简单调用 API 更复杂,也更值得深究。
很多人觉得“大模型接入业务”不就是简单调用接口、传输数据、接收结果吗?
可当我们实际做了才发现,这种看似顺滑的流程,其实非常脆弱。一旦业务稍微复杂,光靠模型 API 堆功能,马上暴露各种问题:上下文丢失、逻辑割裂、输出格式随意。这就像买了一辆超级跑车,却只在狭窄的车库里来回倒腾,根本发挥不了它的真实价值。
我们要的是,让模型真正融入流程。
我们的 Python AI 应用主要实现了四个功能:文档校对、文档生成、智能邮件,以及未来的系统对接展望。
文档校对
第一大功能是文档校对。很多平台已经支持文件上传,但只是粗放地处理。我们设计了专用的 Python 解析脚本,先自动识别文档结构(比如代码的规范格式、财务报表特定指标等),然后结合明确的业务规则调用大模型。这种细致的前置处理,大大提高了模型的输出质量,降低了人工后续的干预。
功能展示:
代码示例:
// 开始核对按钮点击事件 document.getElementById('startCheck').addEventListener('click', async function() { console.log('开始核对按钮被点击'); const preCheckFile = document.getElementById('preCheckFile').files[0]; const billingFiles = document.getElementById('billingReportFiles').files; const steps = document.querySelectorAll('.step'); // 步骤1:解析预核对表 startStep(steps[0], '正在解析预核对表...'); updateProgressBar(1); const preCheckFormData = new FormData(); preCheckFormData.append('file', preCheckFile); try { console.log('开始发送预核对表解析请求'); const preCheckResponse = await fetch('/parse_excel', { method: 'POST', body: preCheckFormData }); console.log('预核对表解析请求响应状态:', preCheckResponse.status); if (!preCheckResponse.ok) throw new Error('预核对表解析失败'); const preCheckResult = await preCheckResponse.json(); parseResults.preCheckData = preCheckResult.data; completeStep(steps[0], `预核对表解析完成,共 ${preCheckResult.data.length} 条记录`); // 修改调用方式,直接传入数据 showPartialData([preCheckResult.data]); } catch (error) { console.error('预核对表解析出错:', error); failStep(steps[0], error.message); return; } // 步骤2:解析计费报表 startStep(steps[1], '正在解析计费报表...'); updateProgressBar(2); try { console.log('开始发送计费报表解析请求'); for (let i = 0; i < billingFiles.length; i++) { const billingFormData = new FormData(); billingFormData.append('file', billingFiles[i]); const billingResponse = await fetch('/parse_excel', { method: 'POST', body: billingFormData }); console.log(`第 ${i + 1} 个计费报表解析请求响应状态:`, billingResponse.status); if (!billingResponse.ok) throw new Error('计费报表解析失败'); const billingResult = await billingResponse.json(); parseResults.billingData.push(billingResult.data); } completeStep(steps[1], `计费报表解析完成,共 ${billingFiles.length} 个文件`); // 修改显示部分解析数据的调用,传入合并后的数据 showPartialData([parseResults.preCheckData, ...parseResults.billingData]); } catch (error) { console.error('计费报表解析出错:', error); failStep(steps[1], error.message); return; } // 步骤3:AI 分析差异 startStep(steps[2], 'AI正在分析差异...'); updateProgressBar(3); // 先检查是否已经存在加载元素,避免重复创建 let loadingElement = document.getElementById('aiLoading'); if (!loadingElement) { loadingElement = document.createElement('div'); loadingElement.id = 'aiLoading'; // 创建加载圈元素 const spinner = document.createElement('div'); spinner.className = 'loading-spinner'; // 创建提示文本元素 const text = document.createElement('span'); text.textContent = 'AI 分析中,请稍候...'; // 将加载圈和提示文本添加到加载提示元素中 loadingElement.appendChild(spinner); loadingElement.appendChild(text); document.body.appendChild(loadingElement); } try { console.log('开始发送 AI 分析差异请求'); const compareResp = await fetch('/compare_and_ask', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pre_check: parseResults.preCheckData, billing: parseResults.billingData }) }); console.log('AI 分析差异请求响应状态:', compareResp.status); if (!compareResp.ok) throw new Error('AI分析差异失败'); const compareResult = await compareResp.json(); parseResults.differences = compareResult.data; // 显示 AI 分析结果 const parsedResultsElement = document.getElementById('parsedResults'); let resultContent = ''; if (compareResult.data) { if (typeof compareResult.data === 'string') { resultContent = compareResult.data; console.log("resultContent", resultContent); } else if (Array.isArray(compareResult.data) || typeof compareResult.data === 'object') { resultContent = `<pre style="white-space: pre-wrap; word-wrap: break-word;">${JSON.stringify(compareResult.data, null, 2)}</pre>`; } } else { resultContent = '未获取到有效的 AI 分析结果'; } if (parsedResultsElement) { parsedResultsElement.innerHTML = resultContent; } else { console.error('未找到 parsedResults 元素'); } completeStep(steps[2], 'AI分析差异完成'); // 移除加载提示 if (loadingElement) { document.body.removeChild(loadingElement); } // 步骤4:生成核对报告 startStep(steps[3], '正在生成核对报告...'); updateProgressBar(4); setTimeout(() => { completeStep(steps[3], '核对报告生成完成'); // 移除切换到核对结果 tab 的逻辑 }, 1000); } catch (error) { console.error('AI 分析差异出错:', error); failStep(steps[2], error.message); // 移除加载提示 if (loadingElement) { document.body.removeChild(loadingElement); } } });
文档生成
第二大功能是文档生成。听起来简单,就是数据填报到报表中,但我们测试发现,GPT 之类的大模型并不擅长处理高度结构化和规则复杂的数据填充。这一步只能依靠 Python 原生脚本实现。我们使用 pandas 等工具,将处理好的结构化数据自动填入模板,实现批量文档输出。
可以实现:一键打印全部,包含8个合同、7个表单样式、97页文档,每月至少节省2人/天工作量。
自动邮件
第三大功能是智能邮件生成和发送。看似简单的邮件自动化,如果仅依靠模型生成内容,常常会缺乏具体业务语境。我们选择了一个巧妙的融合方式:通过前面生成的精准报表结果,让大模型编写出语义清晰且业务贴切的邮件内容,再通过 Python 自动发送邮件,实现无感式的业务流程闭环。
prompt 示例:
你是会议纪要生成专家,请根据如下规则,为每个月不同厂商生成标准格式的项目考核纪要。【目录结构】- 每个目录如 `json/3e9f7a`、`json/2a4b6c` 表示不同月份(如 3e9f7a 表示特定年月);- 每个目录中包含: - `a1b2c3.json`:包含厂商 A、厂商 B、厂商 C 各厂商的解析服务数据、评分、金额等结算信息; - `d4e5f6.json`:包含当月各厂商的考核扣分项目和扣分事由; - `7g8h9i/`:输出纪要存放路径,其中需生成: - `x1.json` → 厂商A 纪要 - `y2.json` → 厂商B 纪要 - `z3.json` → 厂商C 纪要【任务目标】- 根据 `a1b2c3.json` 与 `d4e5f6.json` 两个文件,为每个厂商生成一个标准会议纪要(JSON格式);- 每份纪要内容包括:会议信息、合同名称、考核评分、扣分详情、整改措施、结算信息;- 请按以下映射关系提取数据生成: - `"厂商A"` 对应 `x1.json` - `"厂商B"` 对应 `y2.json` - `"厂商C"` 对应 `z3.json`【输出格式】每个厂商输出一个 JSON 对象,结构统一如下:{ "title": "...", "meeting": { "name": "特定年月考核评审会议纪要", "date": "下一月份", "participants": { "公司X": ["人员A", "人员B", "人员C", "人员D", "人员E", "人员F", "人员G"], "<厂商全称>": ["参会人列表"] } }, "contract": { "name": "...", "contract_number": "如有则填写,否则省略" }, "assessment": { "period": "特定年月", "score_criteria": { "指标1": 40, "指标2": 20, "指标3": 30, "指标4": 10 }, "result": { "评分": "...", "扣分情况": "...", "说明": "..." }, "整改措施": { ...如有扣分则列出... } }, "settlement": { ...每个模块的数据... }, "note": "特此纪要"}【细节要求】- 若某厂商无扣分,写明“扣分情况:无”,说明中突出“支撑稳定、无客户投诉”;- 若有扣分,需写明模块、扣分原因、影响评分、整改方案;- 所有金额含税,税率默认 6%,如有单价不同请按预处理文件给出;- 会议名称与日期需自动根据目录名生成;- 输出格式为 JSON,不能包含其他文字或注释;请依次生成每个厂商的纪要,输出为 `7g8h9i/x1.json`、`y2.json`、`z3.json` 文件内容。
外部对接
第四个功能目前还在规划阶段:接入外部系统。我们希望未来实现系统与系统、模型与模型之间的直接交互。
小结
然而,实现前三个功能的过程中,我们也遇到了不少挑战。
1、首先是环境兼容性问题,比如内外网隔离导致的库依赖冲突。为了避免踩坑,我们严格控制依赖版本,争取做到一次构建,到处稳定运行。
2、其次是架构上的博弈。一开始我们希望打造一个通用的文档解析器,但实际运行后发现,业务场景差异巨大,通用型并不能真正适配所有情况。最终我们转向了“通用解析器 + 定制化脚本”的组合模式,既保持了通用性的框架,又能灵活响应不同业务的特殊需求。
3、最棘手的难点在于,大模型本质上并不会真正“思考”。它擅长的是即时响应,却无法贯穿历史上下文,缺乏整体一致性和逻辑重构的能力。为了解决这个问题,我们采用了代码规则前置、输出后验证、必要时人工闭环的三步组合策略,确保模型输出始终稳定可靠。
经过这一系列尝试,我想分享一个关键洞察:真正落地的大模型应用,不能只靠模型 API 堆叠功能,必须依托脚本能力、系统集成能力,以及业务场景的精准判断。