SSA Agent channel improvements (12 code files, +931/-203 lines): - Solution B: left/right separation of concerns (gaze guiding + state mutex + time-travel) - JWT token refresh mechanism (ensureFreshToken) to fix HTTP 401 during pipeline - Code truncation fix: LLM maxTokens 4000->8000 + CSS max-height 60vh - Retry streaming code generation with generateCodeStream() - R Docker structured errors: 20+ pattern matching + format_agent_error + line extraction - Prompt iron rules: strict output format in CoderAgent System Prompt - parseCode robustness: XML/Markdown/inference 3-tier matching + length validation - consoleOutput type defense: handle both array and scalar from R Docker unboxedJSON - Agent progress bar sync: derive phase from agentExecution.status - Export report / view code buttons restored for Agent mode - ExecutingProgress component: real-time timer + dynamic tips + step pulse animation Architecture design (3 review reports): - Plan-and-Execute step-by-step execution architecture approved - Code accumulation strategy (R Docker stays stateless) - 5 engineering guardrails: XML tags, AST pre-check, defensive prompts, high-fidelity schema, error classification circuit breaker Docs: update SSA module status v4.1, system status v6.7, deployment changelist Made-with: Cursor
97 lines
6.8 KiB
Markdown
97 lines
6.8 KiB
Markdown
# **架构进阶指南:提升 LLM 代码生成与修复成功率的 10 大高级策略**
|
||
|
||
**文档目的:** 针对 Agentic Workflow 中大模型写 R 代码容易报错、陷入死循环的问题,提供系统性的解决方案。
|
||
|
||
**核心逻辑:** 不要指望大模型“不犯错”,而是要建立一套“让它极难犯错,且一旦犯错能立刻定位”的工程护栏。
|
||
|
||
## **🎯 第一部分:提升“首次生成”成功率 (Getting It Right The First Time)**
|
||
|
||
防范于未然永远是成本最低的。为了防止类似 unexpected input(中文泄露到代码区)这种低级语法错误,我们需要在 Prompt 和约束上下狠手:
|
||
|
||
### **1\. 采用 XML 标签强制物理隔离 (XML Tagging)**
|
||
|
||
* **痛点**:传统的 Markdown 代码块 (r ... ) 很容易被大模型破坏,它经常会在反引号外面或者里面夹杂诸如“好的,根据您的要求...”之类的闲聊。
|
||
* **策略**:在 Coder Agent 的 Prompt 中,强制要求它将纯代码包裹在自定义的 XML 标签中。
|
||
* **Prompt 示例**:“你只能输出纯 R 代码。绝对不要输出任何 Markdown 标记、问候语或解释。**你必须且只能将代码放在 \<r\_code\> 和 \</r\_code\> 标签之间。**”
|
||
* **后端解析**:Node.js 提取时直接用正则表达式提取 \<r\_code\> 内部的内容,彻底屏蔽外围的所有文字幻觉。
|
||
|
||
### **2\. 注入“防御性编程”黄金法则 (Defensive Prompting)**
|
||
|
||
* **痛点**:LLM 假设数据是完美的,但实际数据常有 NA、类型错误或极端值,导致 t.test 等函数直接崩溃。
|
||
* **策略**:在 System Prompt 中硬编码医学统计的“防御性 R 编程规范”。
|
||
* **Prompt 示例**:
|
||
“写 R 代码时必须遵守以下防御规则:
|
||
1. 模型计算前,强制剔除涉及变量的 NA 值:df \<- na.omit(df\[, c('X', 'Y')\])
|
||
2. 强制类型转换:把分组变量明确转为因子 as.factor(),把数值变量明确转为数值 as.numeric()。
|
||
3. 如果要做回归,先检查是否只有1个水平,如果只有1个水平直接停止执行。”
|
||
|
||
### **3\. 强制思维链注释化 (Chain of Thought in Comments)**
|
||
|
||
* **痛点**:如果不让大模型“说话”,直接写代码,它的逻辑往往会混乱(缺乏思维链的推演)。
|
||
* **策略**:允许它思考,但**强制它把思考过程写在 R 代码的注释里**。
|
||
* **Prompt 示例**:“在写具体代码前,请先使用 R 语言的注释符号 \# 逐行写下你的分析步骤和推演过程。确保每一行中文的前面都有 \#。”
|
||
|
||
### **4\. 数据字典的高保真注入 (High-Fidelity Schema Injection)**
|
||
|
||
* **痛点**:LLM 写错列名(大小写错误、多加了下划线)。
|
||
* **策略**:不仅仅给 LLM 传入列名数组,最好把每一列的 Class (如 numeric, character) 和**前 3 行的具体数值**(Head)作为 Context 传给 Coder Agent。看到真实的数值长相,LLM 选错变量类型和拼错列名的概率会断崖式下降。
|
||
|
||
## **🛠️ 第二部分:提升“代码修复”成功率 (Making Self-Healing Work)**
|
||
|
||
一旦出错,如何让 Fixer Agent 一次性改对,而不是陷入“修了A错误,引发B错误”的死循环?
|
||
|
||
### **5\. R 端报错的“降维翻译” (Enhancing Error Traceback)**
|
||
|
||
* **痛点**:R 的默认报错极度晦涩(如 Error in eval(expr, envir) : object 'X' not found),不告诉你是哪一行代码报的错。Fixer Agent 拿到这种错误就像盲人摸象。
|
||
* **策略**:在 R Docker 的 plumber.R 外壳中,使用 rlang 包捕获异常,将完整的调用栈和具体的出错行号抛给 Node.js。
|
||
* **R 代码改造**:
|
||
tryCatch({
|
||
eval(parse(text \= input\_code))
|
||
}, error \= function(e) {
|
||
\# 提取具体的报错信息和可能的行号
|
||
error\_msg \<- conditionMessage(e)
|
||
\# 将此结构化错误返回给 Node.js
|
||
stop(paste("\[R\_EXEC\_ERROR\]", error\_msg))
|
||
})
|
||
|
||
### **6\. Fixer Agent 的“上下文重置” (Context Reset)**
|
||
|
||
* **痛点**:如果把错误信息直接 Append 到之前的长对话记录里让模型修改,模型会受之前历史信息的干扰,产生“注意力偏移”。
|
||
* **策略**:Fixer Agent 必须是一个**拥有全新 Context 的独立会话**。
|
||
* **输入构造**:它只需要接收 3 个东西:
|
||
1. \<original\_code\>...原始代码...\</original\_code\>
|
||
2. \<error\_log\>...R引擎的精确报错...\</error\_log\>
|
||
3. \<data\_schema\>...列名和类型...\</data\_schema\>
|
||
* 干净的上下文能让大模型将 100% 的注意力集中在“找 Bug”上。
|
||
|
||
### **7\. 引入 AST (抽象语法树) 静态检查 (Fail Fast)**
|
||
|
||
* **策略**:在 Node.js 把修复后的代码发给 R 之前(或者在 R 引擎运行 eval 之前),先执行纯粹的语法检查。
|
||
* **R 端实现**:使用 parse(text \= code)。如果代码连括号都没闭合、引号没闭合,parse 会立刻报错,根本不需要进入漫长的数据加载和计算环节。这能将修复反馈循环(Feedback Loop)的延迟从几秒缩短到几毫秒。
|
||
|
||
### **8\. 强制输出“诊断报告”再输出代码**
|
||
|
||
* **痛点**:大模型拿到错误后,急于输出代码,往往只是“瞎蒙”一个改法。
|
||
* **策略**:强制要求 Fixer Agent 遵循 Diagnosis \-\> Fix Plan \-\> Code 的标准格式输出。
|
||
* **Prompt 示例**:
|
||
“收到报错后,你必须按以下格式作答:
|
||
1. **错误诊断**:分析 R 报错的根本原因。
|
||
2. **修复方案**:说明你打算修改哪几行代码。
|
||
3. **修正代码**:将修改后的完整代码放在 \<r\_code\> 标签中。”
|
||
|
||
## **🏗️ 第三部分:架构级防线 (Architectural Safeguards)**
|
||
|
||
### **9\. 异常分类与短路机制 (Error Classification & Circuit Breaker)**
|
||
|
||
有些错大模型能修,有些错大模型**绝对修不好**,千万不要浪费 Token 循环重试。
|
||
|
||
在 Node.js 中建立错误拦截字典:
|
||
|
||
* **可重试 (Retriable)**:object not found, unexpected input, could not find function(通常是少加了 library 或拼错变量)。
|
||
* **直接短路 (Hard Abort)**:system is computationally singular (多重共线性,数据数学性质导致,大模型改代码没用), cannot allocate vector of size (内存超限,直接中断并提示用户)。
|
||
|
||
### **10\. 建立“错题本”机制 (Error Memory / RAG for Fixes)**
|
||
|
||
* **终极杀招**:在数据库建一张 ssa\_fixed\_errors 表。
|
||
* **流程**:当某次 R报错 \-\> LLM修复 \-\> 再次执行成功 时,将这个组合 (报错信息 \+ 修复前代码 \-\> 修复后代码) 存入向量数据库。
|
||
* **使用**:下次 Fixer Agent 遇到类似报错时,先从向量库检索历史成功修复案例喂给它。随着系统运行的时间越长,它修 Bug 的能力就越强,最终无限逼近资深 R 程序员。 |