Backend: - Agent core prompts (Planner + Coder) now loaded from PromptService with 3-tier fallback (DB -> cache -> hardcoded) - Seed script (seed-ssa-agent-prompts.ts) for idempotent SSA_AGENT_PLANNER + SSA_AGENT_CODER setup - SSA fallback prompts added to prompt.fallbacks.ts - Phase 5A: XML tag extraction, defensive programming prompt, high-fidelity schema injection, AST pre-check - Default agent mode migration + session CRUD (rename/delete) APIs - R Docker: structured error handling (20+ patterns) + AST syntax pre-check Frontend: - Default agent mode (QPER toggle removed), view code fix, analysis result cards in chat - Session history sidebar with inline rename/delete, robust plan parsing from reviewResult - R code export wrapper for local reproducibility (package checks + data loader + polyfills) - SSA workspace CSS updates for sidebar actions and plan display Docs: - SSA module doc v4.2: Prompt inventory (2 Agent active / 11 QPER archived), dev progress updated - System overview doc v6.8: SSA Agent MVP milestone - Deployment checklist: DB-5 (seed script) + BE-10 (prompt management) Made-with: Cursor
110 lines
5.5 KiB
Markdown
110 lines
5.5 KiB
Markdown
# **架构优化方案:R 代码的本地复现与导出包装 (Export Wrapper)**
|
||
|
||
**问题诊断:** 大模型在 Agent 管线中生成的 R 代码是高度依赖“平台沙箱环境”的。它缺失了数据读取操作 (df),且引用了平台专属的 UI 辅助函数 (make\_table\_block\_from\_df 等)。
|
||
|
||
**解决目标:** 用户点击“下载 R 代码”时,系统必须动态注入“本地兼容层”,使得代码可以在任何一台普通的 RStudio 中一键运行。
|
||
|
||
## **一、 根本解决方案:导出包装器 (Export Wrapper)**
|
||
|
||
当用户点击“下载 R 代码”时,前端不能仅仅把 Agent 生成的代码原样保存为 .R 文件。我们需要像编译器一样,将代码包裹在一个**标准的本地复现模板**中。
|
||
|
||
完整的导出文件应该由 3 个部分拼接而成:
|
||
|
||
1. **数据加载层 (Data Loading)**
|
||
2. **函数兼容层 (Polyfills / Mock Helpers)**
|
||
3. **Agent 生成的核心代码 (Core Logic)**
|
||
|
||
## **二、 包装器代码实现范例**
|
||
|
||
前端或后端在生成下载文件时,请使用以下字符串拼接逻辑:
|
||
|
||
// 伪代码:在前端 SSACodeModal 或后端导出 API 中实现
|
||
function generateDownloadableRCode(agentCode: string, fileName: string): string {
|
||
|
||
const headerAndPolyfills \= \`
|
||
\# \=====================================================================
|
||
\# SSA-Pro 智能统计分析 \- 本地复现脚本
|
||
\# \=====================================================================
|
||
|
||
\# 1\. 自动安装缺失的包 (本地复现安全保障)
|
||
required\_packages \<- c("dplyr", "gtsummary", "base64enc", "ggplot2")
|
||
new\_packages \<- required\_packages\[\!(required\_packages %in% installed.packages()\[,"Package"\])\]
|
||
if(length(new\_packages)) install.packages(new\_packages)
|
||
|
||
suppressPackageStartupMessages({
|
||
library(dplyr)
|
||
library(gtsummary)
|
||
library(base64enc)
|
||
library(ggplot2)
|
||
})
|
||
|
||
\# \=====================================================================
|
||
\# 2\. 数据读取 (请确保数据文件与本脚本在同一目录下)
|
||
\# \=====================================================================
|
||
\# 系统已将您的原始数据名填入,如果路径不同请手动修改:
|
||
file\_name \<- "${fileName}"
|
||
|
||
if (file.exists(file\_name)) {
|
||
if (grepl("\\\\\\\\.csv$", file\_name, ignore.case \= TRUE)) {
|
||
df \<- read.csv(file\_name, stringsAsFactors \= FALSE)
|
||
} else if (grepl("\\\\\\\\.xlsx?$", file\_name, ignore.case \= TRUE)) {
|
||
library(readxl)
|
||
df \<- read\_excel(file\_name)
|
||
}
|
||
} else {
|
||
\# 如果找不到文件,生成测试数据以防代码直接崩溃
|
||
warning(paste("找不到数据文件:", file\_name, "。将使用模拟数据进行演示。"))
|
||
df \<- data.frame(
|
||
root\_curve \= sample(c(1, 2), 100, replace \= TRUE),
|
||
Yqol \= sample(c(0, 1), 100, replace \= TRUE)
|
||
)
|
||
}
|
||
|
||
\# \=====================================================================
|
||
\# 3\. 平台 UI 辅助函数本地兼容层 (Polyfills)
|
||
\# 这使得平台专用的 make\_\*\_block 函数在本地控制台优雅地输出,而不报错
|
||
\# \=====================================================================
|
||
make\_markdown\_block \<- function(text) {
|
||
cat("\\\\n========================================\\\\n")
|
||
cat(text, "\\\\n")
|
||
}
|
||
|
||
make\_table\_block\_from\_df \<- function(data, title="", footnote="") {
|
||
cat("\\\\n---", title, "---\\\\n")
|
||
print(data)
|
||
if(footnote \!= "") cat("注:", footnote, "\\\\n")
|
||
return(list(type="table"))
|
||
}
|
||
|
||
make\_image\_block \<- function(base64\_data, title="", alt="") {
|
||
cat("\\\\n\[图形已生成:", title, "- 请查看 RStudio 的 Plots 面板\]\\\\n")
|
||
return(list(type="image"))
|
||
}
|
||
|
||
make\_kv\_block \<- function(items, title="") {
|
||
cat("\\\\n---", title, "---\\\\n")
|
||
print(unlist(items))
|
||
return(list(type="key\_value"))
|
||
}
|
||
|
||
\# \=====================================================================
|
||
\# 4\. 核心分析代码 (由 AI Agent 生成)
|
||
\# \=====================================================================
|
||
\`;
|
||
|
||
return headerAndPolyfills \+ "\\n" \+ agentCode;
|
||
}
|
||
|
||
## **三、 为什么必须这么做?(架构收益)**
|
||
|
||
1. **防患于未然的数据读取:** 我们不仅注入了 read.csv,还加入了 file.exists 检查。如果医生把 R 脚本发给另一个没有原始数据的统计师,代码会自动生成一组 Mock(模拟)数据。这样 R 脚本无论如何都能跑通,极大提升了产品的专业感。
|
||
2. **优雅的 Polyfills (兼容层) 技术:**
|
||
这是前端工程(如适配老版本浏览器)最常用的技术。我们在脚本头部用普通的 print() 和 cat() 重写了 make\_table\_block\_from\_df 等函数。这样,大模型生成的复杂 UI 代码在本地 RStudio 中执行时,不仅**不会报错**,还会把结果**整齐地打印在本地控制台上**。
|
||
3. **保持 Agent Prompt 的纯净:**
|
||
我们**不需要**去修改 CoderAgent 的 System Prompt 让它“记得写读取文件的代码”。因为每次让 LLM 动态写数据读取逻辑,它很容易因为编码(UTF-8 vs GBK)或文件路径错误而翻车。把这种死板的工作交给前端的字符串拼接(Wrapper),是最稳定、最省 Token 的做法。
|
||
|
||
## **四、 实施建议**
|
||
|
||
请前端团队接手此任务:
|
||
|
||
在 AgentCodePanel.tsx 或 SSACodeModal.tsx 中,找到处理\*\*“导出 R 脚本 (Export/Download .R)”\*\*的 onClick 函数。在生成 Blob 对象并触发浏览器下载之前,将原有的代码字符串通过上述包装器函数处理一遍即可。这只需半小时即可实现。 |