[大模型应用].Net下接入VLM多模态模型分析
目录
一、目的
二、解决方案
2.1 环境说明
2.2 功能实现流程
2.3 代码实现
2.3.1 提示词说明
2.3.2 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
第三方接口:https://api.siliconflow.cn/v1/chat/completions
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
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {ApiKey}");
/// <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 URIvar 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.contentChatResponseSModel? 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接口请求实体
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接口返回实体
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标准方式调用,但是内部核心逻辑是一致。在使用过程也是踩坑不少。
