目录
[2.1 环境说明](#2.1 环境说明)
[2.2 功能实现流程](#2.2 功能实现流程)
[2.3 代码实现](#2.3 代码实现)
[2.3.1 提示词说明](#2.3.1 提示词说明)
[2.3.2 AI接口请求实体](#2.3.2 AI接口请求实体)
[2.3.3 AI接口返回实体](#2.3.3 AI接口返回实体)
一、目的
目前在开发一个健康养生类产品时,考虑用户可以上传自身的病例报告,通过调用AI大模型给出病例报告解读。在实现的过程中碰到了一些问题,最后想着记录一下,避免大家以后踩坑。
首先理解一下什么是多模态模型,多模态模型是能够同时处理多种模态信息(文本、图像、音频、视频)的大语言模型。SiliconFlow 提供了多个支持不同模态组合的强大模型,能够:
- 视觉理解:理解图片内容、OCR、图像描述
- 视频分析:提取视频帧、理解视频内容、动作识别
- 音频处理:语音识别、音频内容分析
- 多模态融合:同时处理多种媒体类型的综合分析
在考虑使用VLM模型解决自己问题时,最开始第一个考虑是使用DeepSeek的开放接口,最开始通过网页版尝试分析图象,并根据提示词给出相关结果,发现是可行的且返回结果还不错。


但后续发现截止文章发布的时间点下,他们的API开放平台中的相关接口目前不支持多模态模型。DeepSeek本身使用VL2和OCR的视觉处理模型,但是在API开放平台中未开放,这个大家要注意。
最后对比硅基流动和百度千帆,选择了硅基流动。两者区别倒是不大,按时尝试了下几个视觉模型的返回结果,感觉硅基流动下处理时间和分析内容都还不错。当然主要是白嫖了14块钱。
对硅基流动感兴趣可以看看这个博文:【大模型应用】初学:硅基流动DeepSeekAI+Cherry-studio使用
二、解决方案
2.1 环境说明
语言:C#
技术框架:.Net6 Asp.Net WebApi
2.2 功能实现流程
这是一个医学报告图像分析服务,通过调用DeepSeek VL2多模态AI模型,对用户上传的医学报告图像进行智能分析和解读。
1、输入处理
- 参数验证:确保imageBase64参数不为空
- 格式兼容:支持原始base64字符串和完整data URI格式
- 自动补全:对原始base64数据自动添加data URI前缀
2、分析流程设计
系统按照严格的医学报告分析步骤:
- 图像类型识别:判断是否为医学报告
- 关键信息提取:患者信息、检查项目、指标数值
- 专业解读:异常指标说明、健康风险评估
3、输出处理
标准化输出:统一的JSON响应格式
2.3 代码实现
以下是一个接口请示例中在进行Http请求时需要请求头信息,同时需要前往硅基流动平台获取ApiKey,接口地址:https://api.siliconflow.cn/v1/chat/completions
cs
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {ApiKey}");
cs
/// <summary>
/// 图像AI分析接口
/// </summary>
/// <param name="imageBase64"></param>
/// <param name="userText"></param>
/// <returns></returns>
public async Task<string> SendChatWithImageAsync(string imageBase64, string userText = "请帮我描述这张图片的内容")
{
if (string.IsNullOrWhiteSpace(imageBase64))
{
return "Error: imageBase64 is required";
}
// 兼容传入 raw base64 或完整 data URI
var trimmed = imageBase64.Trim();
var dataUri = trimmed.StartsWith("data:image", StringComparison.OrdinalIgnoreCase)
? trimmed
: $"data:image/jpeg;base64,{trimmed}";
// 构造图文混合消息
var Sys_Content = new List<ContentItem>
{
new ContentItem { Type = "text", Text = "你是一个专业的医学报告分析助手。" }
};
var User_Content = new List<ContentItem>
{
new ContentItem { Type = "image_url", ImageUrl = new ImageUrl { Url = dataUri } },
new ContentItem { Type = "text", Text = "输入相关提示词内容" }
};
var requestBody = new ChatRequestSModel
{
Model = "deepseek-ai/deepseek-vl2",
Messages = new List<Message>
{
new Message
{
Role = "system",
Content = Sys_Content
},
new Message
{
Role = "user",
Content = User_Content
}
},
MaxTokens = 4096,
ResponseFormat = new ResponseFormat { Type = "json_object" },
Stream = false
};
// 按 reqinfo 结构要求,序列化请求体
var json = JsonSerializer.Serialize(requestBody, new JsonSerializerOptions { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping });
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
var response = await _httpClient.PostAsync(ApiUrl, content);
response.EnsureSuccessStatusCode();
// 获取响应并反序列化为
var responseBytes = await response.Content.ReadAsByteArrayAsync();
var responseContent = Encoding.UTF8.GetString(responseBytes);
// 提取 assistant 的 message.content
ChatResponseSModel? resp = null;
try
{
resp = JsonSerializer.Deserialize<ChatResponseSModel>(responseContent, new JsonSerializerOptions { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping });
}
catch
{
// 反序列化失败则直接返回原始字符串
return responseContent;
}
if (resp?.Choices != null && resp.Choices.Count > 0 && resp.Choices[0]?.Message != null)
{
// content 本身就是一个 JSON 字符串(包含 success/message/content),直接返回该字符串
return resp.Choices[0].Message.Content ?? string.Empty;
}
// 未取到有效内容时返回原始响应,避免信息丢失
return responseContent;
}
catch (Exception ex)
{
return $"Error: {ex.Message}";
}
}
2.3.1 提示词说明
多模态信息在请求时用户可以输出相关提示词,让AI来指导如何对于上传文件进行处理,以下是一个参考的提示词内容。
提示词:
你是一个专业的医学报告分析助手。请按照以下步骤处理用户上传的图像:1. 图像类型识别:首先判断图像是否为医学报告(如CT报告、血液检验单、超声图像等)。若非医学报告,直接返回:{\"success\": false, \"message\": \"请传递医学报告\", \"content\": \"\"} 2. 内容分析:若确认为医学报告,则提取以下关键信息: - 患者基本信息(姓名、年龄、性别) - 检查项目(如MRI、X光、血液分析) - 主要指标与数值 - 医生结论或建议3. 解读方案:基于提取内容,生成通俗易懂的解读: - 异常指标说明及其临床意义 - 可能关联的健康风险 - 建议的后续行动(如复检、专科就诊)4. 输出格式:严格使用以下JSON结构: {\"success\": true, \"message\": \"分析成功\", \"content\": \"报告解读内容以Html格式返回\"} 注意事项:- 若图像模糊或信息不全,在content中注明"部分数据无法识别" - 避免提供未经证实的诊断,仅基于报告客观解读 - 所有医疗建议需标注"仅供参考,具体诊疗请遵医嘱"
2.3.2 AI接口请求实体
cs
public class ChatRequestSModel
{
/// <summary>
/// 模型名称,例如:deepseek-chat
/// </summary>
public string Model { get; set; }
/// <summary>
/// 对话消息列表
/// </summary>
public List<Message> Messages { get; set; } = new List<Message>();
/// <summary>
/// 最大 tokens 限制
/// </summary>
public int MaxTokens { get; set; } = 1024;
/// <summary>
/// 响应格式
/// </summary>
public ResponseFormat ResponseFormat { get; set; }
/// <summary>
/// 是否流式输出
/// </summary>
public bool Stream { get; set; } = false;
}
/// <summary>
/// 单条对话消息
/// </summary>
public class Message
{
/// <summary>
/// 角色,如:user、assistant
/// </summary>
[JsonPropertyName("role")]
public string Role { get; set; }
/// <summary>
/// 多段内容(文本、图片等)
/// </summary>
[JsonPropertyName("content")]
public List<ContentItem> Content { get; set; }
}
/// <summary>
/// 图文内容项
/// </summary>
public class ContentItem
{
/// <summary>
/// 内容类型:text 或 image_url
/// </summary>
[JsonPropertyName("type")]
public string Type { get; set; }
/// <summary>
/// 文本内容(当 type = text 时使用)
/// </summary>
[JsonPropertyName("text")]
public string Text { get; set; }
/// <summary>
/// 图片地址或数据(当 type = image 时使用)
/// </summary>
[JsonPropertyName("image_url")]
public ImageUrl ImageUrl { get; set; }
}
/// <summary>
/// 图片地址或 Base64 数据
/// </summary>
public class ImageUrl
{
/// <summary>
/// 图片 URL(与 data 二选一)
/// </summary>
[JsonPropertyName("url")]
public string Url { get; set; }
[JsonPropertyName("detail")]
public string Detail { get; set; }
}
/// <summary>
/// 响应格式定义
/// </summary>
public class ResponseFormat
{
/// <summary>
/// 类型,如:text
/// </summary>
[JsonPropertyName("type")]
public string Type { get; set; }
}
2.3.3 AI接口返回实体
cs
public class ChatResponseSModel
{
[JsonPropertyName("id")] public string Id { get; set; }
[JsonPropertyName("object")] public string Object { get; set; }
[JsonPropertyName("created")] public long Created { get; set; }
[JsonPropertyName("model")] public string Model { get; set; }
[JsonPropertyName("choices")] public List<Choice> Choices { get; set; } = new List<DeepSeekChoice>();
[JsonPropertyName("usage")] public Usage Usage { get; set; }
[JsonPropertyName("system_fingerprint")] public string SystemFingerprint { get; set; }
}
public class Choice
{
[JsonPropertyName("index")] public int Index { get; set; }
[JsonPropertyName("message")] public DeepSeekMessageResp Message { get; set; }
[JsonPropertyName("finish_reason")] public string FinishReason { get; set; }
}
public class MessageResp
{
[JsonPropertyName("role")] public string Role { get; set; }
// 注意:在响应中 content 是一个字符串(JSON 字符串),与请求时的多段 content 结构不同
[JsonPropertyName("content")] public string Content { get; set; }
}
public class Usage
{
[JsonPropertyName("prompt_tokens")] public int PromptTokens { get; set; }
[JsonPropertyName("completion_tokens")] public int CompletionTokens { get; set; }
[JsonPropertyName("total_tokens")] public int TotalTokens { get; set; }
}
三、文章总结
以上多模态的使用是通过Http直接通过接口请求,没有使用通用的OpenApi标准方式调用,但是内部核心逻辑是一致。在使用过程也是踩坑不少。