# 大模型多模态能力（图片分析）调用示例总结（适配Claude Code规则）
本示例基于 **Angular框架** + **fmode-ng SDK**，调用多模态大模型（`fmode-1.6-cn`）的「视觉识别+文本理解」能力，实现**道德与法治题目图片的全流程处理**（图片OCR识别→结构化提取→答案解析→追问互动），核心是通过「视觉模态」突破纯文本输入限制，实现图片内容的语义化解析。


## 一、核心基础信息
### 1.1 技术栈与依赖
| 类别         | 具体内容                                                                 |
|--------------|--------------------------------------------------------------------------|
| 框架         | Angular（依赖注入`@Injectable`，服务级复用）                             |
| 核心SDK      | `fmode-ng`（提供多模态调用`completionJSON`、聊天流式输出`FmodeChatCompletion`） |
| 数据存储     | Parse（`SurveyItem`存储题目/解析，`SurveyLog`存储搜题日志）               |
| 多模态模型   | `fmode-1.6-cn`（支持视觉+文本双模态，核心用于图片题目识别）               |


### 1.2 关键常量定义（固定配置）
```typescript
// 1. 多模态任务模板（关联后端模板逻辑）
export const DaofaQuestionRecognitionTplCode = 'daofa-question-recognition-tpl'; // 题目识别模板
export const DaofaQATplCode = 'daofa-qa-tpl'; // 问答/追问模板
// 2. 多模态模型标识（必须指定支持视觉的模型）
export const DaofaModel = 'fmode-1.6-cn';
```


## 二、多模态核心能力：图片题目识别（核心流程）
### 2.1 功能描述
通过大模型「视觉能力」解析上传的题目图片（如试卷、练习册拍照），将图片中的文字（题干、选项、材料）转化为**结构化JSON数据**（题型、关键词、选项等），是整个流程的「多模态入口」。

### 2.2 代码实现与规则要点
```typescript
/**
 * 多模态核心：识别题目图片（视觉+文本）
 * @param options.images 图片数组（需为Base64格式，大模型视觉输入标准格式）
 * @param options.onProgressChange 进度回调（如“正在识别题目内容...”）
 * @returns 结构化存储的题目对象（SurveyItem）
 */
async recognizeQuestion(options: {
  images: string[]; // 关键：图片输入（Base64字符串数组，支持多图）
  onProgressChange?: (progress: string) => void;
  loading?: any;
}): Promise<FmodeObject> {
  return new Promise(async (resolve, reject) => {
    try {
      // 1. 多模态提示词设计（规则1：结构化提示，强制输出JSON格式）
      const prompt = `请识别图片中的道德与法治题目，并按以下JSON格式输出：
{
  "questionType": "题型(single-choice/multi-choice/judge/short-answer/material-analysis)",
  "title": "题目标题或简述",
  "content": "完整的题目内容",
  "options": [{"label": "A", "value": "选项内容"}],
  "material": "材料内容(如有)",
  "keywords": ["关键词1", "关键词2"] // 如“宪法、权利、义务”
}
要求：
1. 准确识别题干、选项、材料的文字（含标点）；
2. 严格匹配题型枚举值，不可自定义；
3. 关键词需贴合道德与法治学科核心概念。`;

      // 2. 输出格式约束（规则2：提供JSON示例，降低大模型输出偏差）
      const output = `{
  "questionType": "single-choice",
  "title": "宪法基本权利题",
  "content": "下列属于公民基本权利的是？",
  "options": [{"label": "A", "value": "依法纳税"}],
  "material": "",
  "keywords": ["公民基本权利", "宪法"]
}`;

      // 3. 调用多模态能力（规则3：视觉识别必须配置vision=true + 传入images）
      const questionData = await completionJSON(
        prompt,          // 文本提示词
        output,          // 输出格式示例
        (content) => {   // 增量回调（可选，用于进度更新）
          options.loading?.message = `正在识别题目...${content?.length || 0}字`;
        },
        2,               // 重试次数
        {
          model: DaofaModel,  // 指定多模态模型
          vision: true,       // 启用视觉能力（核心开关）
          images: options.images  // 传入图片数组（Base64）
        }
      );

      // 4. 结果校验（规则4：多模态输出必须先判空，避免后续流程异常）
      if (!questionData || !questionData.content) {
        throw new Error('题目识别结果为空（图片无有效文字或识别失败）');
      }

      // 5. 数据持久化（规则5：识别结果映射到标准存储对象SurveyItem）
      const surveyItem = await this.saveSurveyItem({
        type: 'daofa',                  // 学科标识
        title: questionData.title || '未命名道德与法治题目',
        content: questionData.content,  // 识别后的题干
        images: options.images,         // 关联原始图片
        keywords: questionData.keywords || [],
        options: questionData.options || [],
        createOptions: {
          tpl: DaofaQuestionRecognitionTplCode,
          params: {
            questionType: questionData.questionType,
            recognitionMode: 'image-ocr', // 标记为“图片OCR识别”来源
            material: questionData.material
          }
        }
      });

      resolve(surveyItem);
    } catch (err: any) {
      reject(new Error(`图片识别失败：${err.message || '未知错误'}`));
    }
  });
}
```


## 三、配套能力：基于多模态结果的文本延伸
### 3.1 功能1：答案与解析生成（纯文本模态，依赖图片识别结果）
将图片识别后的结构化题目（题干、选项、题型）传入大模型，生成符合「道德与法治学科规范」的解析（含标准答案、知识点、易错点等），支持**流式输出**（实时更新内容）。

```typescript
async generateAnswer(options: {
  surveyItem: FmodeObject; // 图片识别后的题目对象
  onContentChange?: (content: string) => void; // 流式内容回调
}): Promise<FmodeObject> {
  return new Promise(async (resolve, reject) => {
    try {
      // 1. 从图片识别结果中提取关键信息（规则：复用多模态输出的结构化数据）
      const { content: questionContent, options: questionOptions } = options.surveyItem.attributes;
      const questionType = options.surveyItem.get('createOptions').params.questionType;

      // 2. 结构化提示词（规则：按学科要求分模块，确保解析专业度）
      const prompt = `作为道德与法治教师，解析以下题目：
题目类型：${questionType}
题目内容：${questionContent}
${questionOptions.length ? `选项：\n${questionOptions.map(opt => `${opt.label}. ${opt.value}`).join('\n')}` : ''}

要求按以下格式输出：
【标准答案】（选择题需标注选项，如“A”；简答题需分点）
【知识点】（关联教材章节/法律条文，如“《宪法》第33条 公民在法律面前一律平等”）
【解题思路】（初中生易懂，结合生活实例）
【易错点】（如“混淆‘权利’与‘义务’，依法纳税是义务而非权利”）
【知识拓展】（关联时政热点，如“2024年法治宣传周主题”）`;

      // 3. 流式调用（规则：使用FmodeChatCompletion实现实时内容更新）
      const completion = new (await import('fmode-ng/lib/core/agent')).FmodeChatCompletion(
        [{ role: 'user', content: prompt }], // 上下文
        { model: DaofaModel }
      );

      const subscription = completion.sendCompletion({ isDirect: true }).subscribe({
        next: (message: any) => {
          const content = message.content || '';
          options.onContentChange?.(content); // 实时更新前端解析内容

          // 当输出完成时，保存解析结果并标记选择题正确答案
          if (message.complete && content) {
            options.surveyItem.set('answer', content);
            // 提取正确答案（如从“【标准答案】A”中匹配选项）
            if (questionType.includes('choice')) {
              const correctLabel = this.extractCorrectAnswer(content);
              if (correctLabel) {
                const updatedOptions = questionOptions.map(opt => ({
                  ...opt,
                  check: opt.label === correctLabel // 标记正确选项
                }));
                options.surveyItem.set('options', updatedOptions);
              }
            }
            options.surveyItem.save().then(resolve);
          }
        },
        error: (err) => reject(new Error(`解析生成失败：${err.message}`))
      });
    } catch (err: any) {
      reject(new Error(`解析生成失败：${err.message}`));
    }
  });
}
```


### 3.2 功能2：用户追问处理（上下文模态，闭环互动）
基于已识别的题目和解析，处理用户的后续疑问（如“为什么这个选项不对？”），需传入历史上下文确保回答连贯性。

```typescript
async handleQuestion(options: {
  parentQuestion: FmodeObject; // 原始题目（图片识别结果）
  userQuestion: string;        // 用户追问内容
}): Promise<FmodeObject> {
  return new Promise(async (resolve, reject) => {
    try {
      // 1. 拼接上下文（规则：必须包含原始题目+已有解析，避免回答脱离场景）
      const parentContent = options.parentQuestion.get('content');
      const parentAnswer = options.parentQuestion.get('answer');
      const prompt = `基于以下题目和解析，回答学生的追问：
题目内容：${parentContent}
已有解析：${parentAnswer}
学生追问：${options.userQuestion}

要求：
1. 针对追问精准回应，不偏离原始题目；
2. 用“启发式”语言（如“你可以先回顾‘权利与义务的区别’，再看选项是否符合权利的定义”）；
3. 引用教材/法律条文时标注出处。`;

      // 2. 调用大模型并保存追问记录
      const completion = new (await import('fmode-ng/lib/core/agent')).FmodeChatCompletion(
        [{ role: 'user', content: prompt }],
        { model: DaofaModel }
      );

      completion.sendCompletion({ isDirect: true }).subscribe({
        next: async (message: any) => {
          if (message.complete && message.content) {
            // 保存追问记录到SurveyItem（类型为daofa-qa）
            const qaItem = await this.saveQuestionAnswer({
              parent: options.parentQuestion,
              question: options.userQuestion,
              answer: message.content
            });
            resolve(qaItem);
          }
        },
        error: (err) => reject(new Error(`追问回答失败：${err.message}`))
      });
    } catch (err: any) {
      reject(new Error(`追问处理失败：${err.message}`));
    }
  });
}
```


## 四、Claude Code 核心规则提炼
### 4.1 多模态调用强制规则
1. **视觉能力启用**：调用`completionJSON`实现图片识别时，必须在参数中配置 `{ vision: true, images: 图片数组（Base64格式）, model: 多模态模型（如fmode-1.6-cn） }`，缺一不可；
2. **图片格式要求**：`images`参数需为「Base64字符串数组」（前端上传图片需先转Base64，不可直接传URL）；
3. **输出稳定性**：必须通过「结构化提示词+输出示例」约束大模型输出（如指定JSON字段、枚举值），避免非结构化内容导致解析异常。


### 4.2 提示词设计规范
1. **学科约束**：针对垂直领域（如道德与法治），需在提示词中明确「专业要求」（如“引用法律条文需标注出处”“符合初中生认知水平”）；
2. **格式约束**：输出需分模块/JSON结构时，必须提供「完整示例」（如`output`参数的JSON模板），降低大模型输出偏差；
3. **上下文完整性**：追问/解析生成时，必须包含「原始题目+历史结果」（如`parentContent`+`parentAnswer`），避免回答脱离场景。


### 4.3 流程链路规则
1. **数据依赖**：图片识别（`recognizeQuestion`）是前置流程，后续的解析生成（`generateAnswer`）、追问（`handleQuestion`）必须依赖其输出的`SurveyItem`对象；
2. **结果校验**：多模态输出（`questionData`）需先校验「非空+关键字段存在」（如`content`、`questionType`），再进入存储/后续流程；
3. **流式处理**：使用`FmodeChatCompletion`时，需通过`next`事件处理增量内容（实时更新UI），`complete`事件触发结果保存，避免数据丢失。


### 4.4 数据存储规则
1. **对象区分**：`SurveyItem`用于存储「题目/解析/追问」，需通过`type`字段区分（`daofa`=原始题目，`daofa-qa`=追问记录）；
2. **日志跟踪**：`SurveyLog`需记录「搜题模式（图片/OCR）、上传图片、识别耗时」，用于后续统计与问题排查；
3. **关联关系**：追问记录（`daofa-qa`类型`SurveyItem`）需通过`parent`字段关联原始题目，确保上下文链路可追溯。


## 五、完整流程链路
```mermaid
graph TD
    A[用户上传道德与法治题目图片] --> B[图片转Base64格式]
    B --> C[调用recognizeQuestion（多模态视觉识别）]
    C --> D{识别结果校验}
    D -- 失败 --> E[抛出“识别失败”错误]
    D -- 成功 --> F[保存为SurveyItem（type=daofa）]
    F --> G[调用generateAnswer（文本解析生成）]
    G --> H[流式输出解析内容，标记选择题正确答案]
    H --> I[用户发起追问（如“为什么B选项错误？”）]
    I --> J[调用handleQuestion（上下文互动）]
    J --> K[保存为SurveyItem（type=daofa-qa，关联parent题目）]
    K --> L[更新SurveyLog（记录追问次数、耗时）]
```