C#学习:基于LLM的简历评估程序

article/2025/8/25 12:51:02

前言

在pocketflow的例子中看到了一个基于LLM的简历评估程序的例子,感觉还挺好玩的,为了练习一下C#,我最近使用C#重写了一个。

准备不同的简历:

image-20250528183949844

查看效果:

image-20250528184200364

image-20250528184258947

不足之处是现实的简历应该是pdf格式的,后面可以考虑转化为图片然后用VLM来试试。

C#学习

在使用C#重写的过程中,学习到的一些东西。

KeyValuePair学习

使用到了KeyValuePair

KeyValuePair<TKey, TValue> 是 C# 中一个用于表示键值对的结构体(struct),它是一个泛型类型,可以存储两个相关联的值:一个键(key)和一个值(value)。

主要特点:

不可变性:KeyValuePair 是一个只读结构,一旦创建就不能修改其键或值。

泛型实现

public struct KeyValuePair<TKey, TValue>

其中 TKey 是键的类型,TValue 是值的类型。

使用示例:

// 创建 KeyValuePair
KeyValuePair<string, int> pair = new KeyValuePair<string, int>("Age", 25);// 访问键和值
Console.WriteLine($"Key: {pair.Key}"); // 输出: Key: Age
Console.WriteLine($"Value: {pair.Value}"); // 输出: Value: 25// 在集合中使用
List<KeyValuePair<string, int>> pairs = new List<KeyValuePair<string, int>>
{new KeyValuePair<string, int>("John", 25),new KeyValuePair<string, int>("Mary", 30)
};

KeyValuePair 通常在以下场景中使用:

作为 Dictionary 的枚举结果

Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("One", 1);
dict.Add("Two", 2);foreach (KeyValuePair<string, int> kvp in dict)
{Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}

方法返回键值对

public KeyValuePair<string, int> GetPersonInfo()
{return new KeyValuePair<string, int>("Age", 25);
}

LINQ 操作中

var dict = new Dictionary<string, int>();
// ... 添加一些数据
var filtered = dict.Where(kvp => kvp.Value > 10).Select(kvp => kvp.Key);

需要注意的是,如果需要可修改的键值对集合,应该使用 Dictionary<TKey, TValue> 而不是 KeyValuePair 的集合。Dictionary 提供了更多的功能和更好的性能。KeyValuePair 主要用于表示单个键值对关系,特别是在遍历或传递数据时。

YAML内容解析

根据这个提示词:

                string prompt = $@"
评估以下简历并确定候选人是否符合高级技术职位的要求。
资格标准:
- 至少具有相关领域的学士学位
- 至少3年相关工作经验
- 与职位相关的强大技术技能简历内容:
{content}请以YAML格式返回您的评估:
```yaml
candidate_name: [候选人姓名]
qualifies: [true/false]
reasons:- [资格认定/不认定的第一个原因]- [第二个原因(如果适用)]
```
";

LLM会返回一个YAML格式的内容,如下所示:

image-20250528190501147

需要解析这个YAML格式内容。

 public static Dictionary<string, object> ParseSimpleYaml(string yaml){var result = new Dictionary<string, object>();string[] lines = yaml.Split('\n');string currentKey = null;List<string> currentList = null;int currentIndentation = 0;for (int i = 0; i < lines.Length; i++){string line = lines[i].Trim();if (string.IsNullOrEmpty(line) || line.StartsWith("#"))continue;int indentation = lines[i].TakeWhile(c => c == ' ').Count();// Handle list itemsif (line.StartsWith("- ")){if (currentList == null){currentList = new List<string>();result[currentKey] = currentList;}string listItem = line.Substring(2).Trim();currentList.Add(listItem);continue;}// Parse key-value pairsint colonIndex = line.IndexOf(':');if (colonIndex > 0){currentKey = line.Substring(0, colonIndex).Trim();string value = line.Substring(colonIndex + 1).Trim();currentIndentation = indentation;currentList = null;// Check if this is a multi-line value with |if (value == "|"){StringBuilder multiline = new StringBuilder();i++;// Collect all indented lineswhile (i < lines.Length && (lines[i].StartsWith("    ") || string.IsNullOrWhiteSpace(lines[i]))){if (!string.IsNullOrWhiteSpace(lines[i]))multiline.AppendLine(lines[i].Substring(4)); // Remove indentationi++;}i--; // Step back to process the next non-indented line in the outer loopresult[currentKey] = multiline.ToString().Trim();}else if (!string.IsNullOrEmpty(value)){// Simple key-valueresult[currentKey] = value;}}}return result;}

解析结果:

image-20250528190559917

C#条件运算符和空合并运算符

 string name = evaluation.TryGetValue("candidate_name", out var candidateNameValue)? candidateNameValue?.ToString() ?? "未知": "未知";

evaluation.TryGetValue(“candidate_name”, out var candidateNameValue)

  • TryGetValue 是 Dictionary 类的一个方法

  • 它尝试获取键为 “candidate_name” 的值

  • 如果找到了值,返回 true,并将值存储在 candidateNameValue 变量中

  • 如果没找到值,返回 false,candidateNameValue 将为默认值

? 条件运算符(三元运算符)

  • 格式为:condition ? value IfTrue : value If False

  • 如果 TryGetValue 返回 true,执行 :前面的部分

  • 如果 TryGetValue 返回 false,执行 : 后面的 “未知”

candidateNameValue?.ToString()

?. 是空条件运算符

  • 如果 candidateNameValue 不为 null,则调用 ToString()

  • 如果 candidateNameValue 为 null,则返回 null

?? “未知”

?? 是空合并运算符

  • 如果左边的值为 null,则使用右边的值(“未知”)

动态类型转换

List<Dictionary<string, object>> evaluations = null;
var objectList = shared["evaluations"] as List<object>;if (objectList != null)
{evaluations = objectList.Select(item => item as Dictionary<string, object>).Where(dict => dict != null).ToList();
}

这种写法是因为在C#中处理动态类型转换时需要特别小心,尤其是在处理集合类型时。

  1. 首先,shared 是一个 Dictionary<string, object>,这意味着存储在其中的值都是 object 类型。

  2. shared[“evaluations”] 实际上存储的是一个列表,但由于存在字典中时是 object 类型,我们需要安全地将其转换回实际的类型。

  3. 代码使用了两步转换的原因是:

  • 第一步:var objectList = shared[“evaluations”] as List;

这一步将 object 转换为 List,因为列表中的每个元素此时仍然是 object 类型

  evaluations = objectList.Select(item => item as Dictionary<string, object>).Where(dict => dict != null).ToList();

这一步将列表中的每个 object 转换为 Dictionary<string, object>,因为每个评估结果实际上是一个字典

使用 as 操作符而不是直接类型转换(比如 (List)shared[“evaluations”])的原因是:

  • as 操作符在转换失败时会返回 null,而不是抛出异常

  • 这样可以安全地进行类型检查和转换,避免运行时错误

使用 Where(dict => dict != null) 可以过滤掉任何转换失败的项,确保最终的列表中只包含有效的字典对象

这种写法虽然看起来有点复杂,但它是一种安全和健壮的方式来处理动态类型转换,特别是在处理可能包含不同类型数据的集合时。这种方式可以:

  • 避免运行时异常

  • 确保类型安全

  • 优雅地处理可能的空值或无效数据

最后

全部代码已上传至GitHub,地址:https://github.com/Ming-jiayou/PocketFlowSharp/tree/main/PocketFlowSharpSamples.Console/Resume_Qualification_Demo

推荐阅读

“Pocket Flow,一个仅用 100 行代码实现的 LLM 框架”

使用PocketFlow构建Web Search Agent

手把手教你使用C#创建一个WebSearchAgent

使用PocketFlowSharp创建一个Human_Evaluation示例


http://www.hkcw.cn/article/kBudUVgqkb.shtml

相关文章

华为OD机试真题——阿里巴巴找黄金宝箱(II)(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

最大流-Ford-Fulkerson增广路径算法py/cpp/Java三语言实现

最大流-Ford-Fulkerson增广路径算法py/cpp/Java三语言实现 一、网络流问题与相关概念1.1 网络流问题定义1.2 关键概念 二、Ford-Fulkerson算法原理2.1 核心思想2.2 算法步骤 三、Ford-Fulkerson算法的代码实现3.1 Python实现3.2 C实现3.3 Java实现 四、Ford-Fulkerson算法的时间…

摄像头模块的镜头类型

一、‌按光学功能分类‌ ‌球面镜&#xff08;Spherical Lens&#xff09;‌ ‌特点‌&#xff1a;表面为球面曲率&#xff0c;工艺简单且成本低&#xff0c;但存在球面像差和色差&#xff0c;边缘画质易模糊。 ‌应用‌&#xff1a;低端监控设备、玩具相机等对画质要求低的…

汽车EPS系统的核心:驱动芯片的精准控制原理

随着科技的飞速发展&#xff0c;电机及其驱动技术在现代工业、汽车电子、家用电器等领域扮演着越来越重要的角色。有刷马达因其结构简单、成本低廉、维护方便等优点&#xff0c;在市场上占据了一定的份额。然而&#xff0c;为了充分发挥有刷马达的性能&#xff0c;一款高效能、…

51c视觉~3D~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/13954440 #SceneTracker 在4D时空中追踪万物&#xff01;国防科大提出首个长时场景流估计方法 本篇分享 TPAMI 2025 论文​​SceneTracker: Long-term Scene Flow Estimation Network​​&#xff0c;国防科大提出首…

【25-cv-05855】Keith律所代理Paula Alejandra Navarro 版权图

Paula Alejandra Navarro 版权图 案件号&#xff1a;25-cv-05855 立案时间&#xff1a;2025年5月27日 原告&#xff1a;Paula Alejandra Navarro 代理律所&#xff1a;Keith 原告介绍 原告是来自巴拿马的自由职业艺术家&#xff0c;擅长将精灵、中世纪服饰等经典奇幻元素…

vue自定义穿梭框(内容体+多选框)

最近需要做一个资源分配的一个功能&#xff0c;然后用到了穿梭框&#xff0c;但是需要更多的功能控制。具体业务场景如下&#xff1a;需要同时可以分配查看和下载的权限。实现效果如下&#xff1a; 组件用的是&#xff1a; Ant Design Vue 的穿梭框 操作方式&#xff1a;在左…

各国竞争的下一代液晶技术:中国铁电液晶取得重大突破突破

一、全球下一代液晶技术发展格局 &#xff08;一&#xff09;韩国&#xff1a;OLED 技术持续领先&#xff0c;布局量子点与柔性显示 韩国作为显示产业强国&#xff0c;三星、LG 等企业在 OLED 领域占据全球主导地位。三星的 AMOLED 技术广泛应用于高端智能手机&#xff0c;其柔…

张亚中提打败赖清德唯一策略 促两岸和平共识

随着国民党主席朱立伦任期即将届满,台湾孙文学校总校长张亚中已于21日宣布参选党主席。张亚中表示,国民党需要一个政策与路线的大辩论,包括两岸关系的核心问题和定位。他认为,若无此策略,国民党难以凭借资历、战力或团结击败现任台湾地区领导人赖清德重返执政。张亚中在接…

《深度关系-从建立关系到彼此信任》

陈海贤老师推荐的书&#xff0c;花了几个小时&#xff0c;感觉现在的人与人之间特别缺乏这种深度的关系&#xff0c;但是与一个人建立深度的关系并没有那么简单&#xff0c;反正至今为止&#xff0c;自己好像没有与任何一个人建立了这种深度的关系&#xff0c;那种双方高度同频…

LLaMaFactory - 支持的模型和模板 常用命令

一、 环境准备 激活LLaMaFactory环境&#xff0c;进入LLaMaFactory目录 cd LLaMA-Factoryconda activate llamafactory 下载模型 #模型下载 from modelscope import snapshot_download model_dir snapshot_download(Qwen/Qwen2.5-0.5B-Instruct) 二、启动一个 Qwen3-0.6B…

数据结构——优先级队列(PriorityQueue)

1.优先级队列 优先级队列可以看作队列的另一个版本&#xff0c;队列的返回元素是由是由插入顺序决定的&#xff0c;先进先出嘛&#xff0c;但是有时我们可能想要返回优先级较高的元素&#xff0c;比如最大值&#xff1f;这种场景下就由优先级队列登场。 优先级队列底层是由堆实…

学习如何设计大规模系统,为系统设计面试做准备!

前言 在当今快速发展的技术时代&#xff0c;系统设计能力已成为衡量一名软件工程师专业素养的重要标尺。随着云计算、大数据、人工智能等领域的兴起&#xff0c;构建高性能、可扩展且稳定的系统已成为企业成功的关键。然而&#xff0c;对于许多工程师而言&#xff0c;如何有效…

负载电容匹配:晶振电路设计中被忽视的隐形杀手

在电子电路的复杂世界里&#xff0c;晶振电路作为频率控制的核心部件&#xff0c;其稳定性和准确性对整个系统的性能起着举足轻重的作用。晶振就如同电子设备的“心脏起搏器”&#xff0c;精准地控制着电路的运行节奏。然而&#xff0c;在众多影响晶振电路性能的因素中&#xf…

Python Day36 学习

对列表、字典、元组、集合进行总结 浙大疏锦行 摘自讲义 机器学习管道Pipeline Q1. 什么是机器学习管道Pipeline&#xff1f; 摘自讲义 Q. 关于“转换器”&#xff1f; 摘自讲义 # 导入StandardScaler转换器 from sklearn.preprocessing import StandardScaler# 初始化转换…

003 flutter初始文件讲解(2)

1.书接上回 首先&#xff0c;我们先来看看昨天最后的代码及展示效果&#xff1a; import "package:flutter/material.dart";void main(){runApp(MaterialApp(home:Scaffold(appBar:AppBar(title:Text("The World")), body:Center(child:Text("Hello…

深入理解C#中的LINQ:数据查询的终极利器

在现代软件开发中&#xff0c;数据处理和查询是几乎所有应用程序的核心需求。无论是从数据库检索数据、过滤内存中的集合&#xff0c;还是解析XML文档&#xff0c;开发者都需要高效、灵活的方式来操作数据。C# 提供的 LINQ&#xff08;Language Integrated Query&#xff0c;语…

133.在 Vue3 中使用 OpenLayers 实现画多边形、任意编辑、遮罩与剪切处理功能

&#x1f3ac; 效果演示截图&#xff08;先睹为快&#xff09; ✨ 功能概览&#xff1a; ✅ 鼠标画任意形状多边形&#xff1b; ✏️ 点击“修改边界”可拖动顶点&#xff1b; &#x1f7e5; 点击“遮罩”后地图除多边形区域外变红&#xff1b; ✂️ 点击“剪切”后仅显示选…

爬虫到智能数据分析:Bright Data × Kimi 智能洞察亚马逊电商产品销售潜力

前言 电商数据分析在现代商业中具有重要的战略价值&#xff0c;通过对消费者行为、销售趋势、商品价格、库存等数据的深入分析&#xff0c;企业能够获得对市场动态的精准洞察&#xff0c;优化运营决策&#xff0c;预测市场趋势、优化广告投放、提升供应链效率&#xff0c;并通…

2025年信息素养大赛 图形化编程复赛 官方样题绘制图形答案解析

今天给大家做一下2025年全国青少年信息素养大赛 图形化编程复赛、决赛官方样题1 编程题&#xff0c;绘制图形及答案解析。 题外话&#xff1a;2024年对Scratch画笔画图考的比较多&#xff0c;例如7月20日的复赛小高组就考了4道数形结合的画图编程题&#xff0c;点击查看&#x…