找回密码
 立即注册
首页 业界区 安全 C#学习:基于LLM的简历评估程序

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

威割 2025-5-30 14:36:05
前言

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

查看效果:
2.png

3.png

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

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

使用到了KeyValuePair。
KeyValuePair 是 C# 中一个用于表示键值对的结构体(struct),它是一个泛型类型,可以存储两个相关联的值:一个键(key)和一个值(value)。
主要特点:
不可变性:KeyValuePair 是一个只读结构,一旦创建就不能修改其键或值。
泛型实现
  1. public struct KeyValuePair<TKey, TValue>
复制代码
其中 TKey 是键的类型,TValue 是值的类型。
使用示例:
  1. // 创建 KeyValuePair
  2. KeyValuePair<string, int> pair = new KeyValuePair<string, int>("Age", 25);
  3. // 访问键和值
  4. Console.WriteLine($"Key: {pair.Key}"); // 输出: Key: Age
  5. Console.WriteLine($"Value: {pair.Value}"); // 输出: Value: 25
  6. // 在集合中使用
  7. List<KeyValuePair<string, int>> pairs = new List<KeyValuePair<string, int>>
  8. {
  9.     new KeyValuePair<string, int>("John", 25),
  10.     new KeyValuePair<string, int>("Mary", 30)
  11. };
复制代码
KeyValuePair 通常在以下场景中使用:
作为 Dictionary 的枚举结果
  1. Dictionary<string, int> dict = new Dictionary<string, int>();
  2. dict.Add("One", 1);
  3. dict.Add("Two", 2);
  4. foreach (KeyValuePair<string, int> kvp in dict)
  5. {
  6.     Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
  7. }
复制代码
方法返回键值对
  1. public KeyValuePair<string, int> GetPersonInfo()
  2. {
  3.     return new KeyValuePair<string, int>("Age", 25);
  4. }
复制代码
LINQ 操作中
  1. var dict = new Dictionary<string, int>();
  2. // ... 添加一些数据
  3. var filtered = dict.Where(kvp => kvp.Value > 10)
  4.                   .Select(kvp => kvp.Key);
复制代码
需要注意的是,如果需要可修改的键值对集合,应该使用 Dictionary 而不是 KeyValuePair 的集合。Dictionary 提供了更多的功能和更好的性能。KeyValuePair 主要用于表示单个键值对关系,特别是在遍历或传递数据时。
YAML内容解析

根据这个提示词:
  1.                 string prompt = $@"
  2. 评估以下简历并确定候选人是否符合高级技术职位的要求。
  3. 资格标准:
  4. - 至少具有相关领域的学士学位
  5. - 至少3年相关工作经验
  6. - 与职位相关的强大技术技能
  7. 简历内容:
  8. {content}
  9. 请以YAML格式返回您的评估:
  10. ```yaml
  11. candidate_name: [候选人姓名]
  12. qualifies: [true/false]
  13. reasons:
  14.   - [资格认定/不认定的第一个原因]
  15.   - [第二个原因(如果适用)]
  16. ```
  17. ";
复制代码
LLM会返回一个YAML格式的内容,如下所示:
4.png

需要解析这个YAML格式内容。
  1. public static Dictionary<string, object> ParseSimpleYaml(string yaml)
  2. {
  3.      var result = new Dictionary<string, object>();
  4.      string[] lines = yaml.Split('\n');
  5.      string currentKey = null;
  6.      List<string> currentList = null;
  7.      int currentIndentation = 0;
  8.      for (int i = 0; i < lines.Length; i++)
  9.      {
  10.          string line = lines[i].Trim();
  11.          if (string.IsNullOrEmpty(line) || line.StartsWith("#"))
  12.              continue;
  13.          int indentation = lines[i].TakeWhile(c => c == ' ').Count();
  14.          // Handle list items
  15.          if (line.StartsWith("- "))
  16.          {
  17.              if (currentList == null)
  18.              {
  19.                  currentList = new List<string>();
  20.                  result[currentKey] = currentList;
  21.              }
  22.              string listItem = line.Substring(2).Trim();
  23.              currentList.Add(listItem);
  24.              continue;
  25.          }
  26.          // Parse key-value pairs
  27.          int colonIndex = line.IndexOf(':');
  28.          if (colonIndex > 0)
  29.          {
  30.              currentKey = line.Substring(0, colonIndex).Trim();
  31.              string value = line.Substring(colonIndex + 1).Trim();
  32.              currentIndentation = indentation;
  33.              currentList = null;
  34.              // Check if this is a multi-line value with |
  35.              if (value == "|")
  36.              {
  37.                  StringBuilder multiline = new StringBuilder();
  38.                  i++;
  39.                  // Collect all indented lines
  40.                  while (i < lines.Length && (lines[i].StartsWith("    ") || string.IsNullOrWhiteSpace(lines[i])))
  41.                  {
  42.                      if (!string.IsNullOrWhiteSpace(lines[i]))
  43.                          multiline.AppendLine(lines[i].Substring(4)); // Remove indentation
  44.                      i++;
  45.                  }
  46.                  i--; // Step back to process the next non-indented line in the outer loop
  47.                  result[currentKey] = multiline.ToString().Trim();
  48.              }
  49.              else if (!string.IsNullOrEmpty(value))
  50.              {
  51.                  // Simple key-value
  52.                  result[currentKey] = value;
  53.              }
  54.          }
  55.      }
  56.      return result;
  57. }
复制代码
解析结果:
5.png

C#条件运算符和空合并运算符
  1. string name = evaluation.TryGetValue("candidate_name", out var candidateNameValue)
  2.      ? candidateNameValue?.ToString() ?? "未知"
  3.      : "未知";
复制代码
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,则使用右边的值("未知")
动态类型转换
  1. List<Dictionary<string, object>> evaluations = null;
  2. var objectList = shared["evaluations"] as List<object>;
  3. if (objectList != null)
  4. {
  5.     evaluations = objectList
  6.         .Select(item => item as Dictionary<string, object>)
  7.         .Where(dict => dict != null)
  8.         .ToList();
  9. }
复制代码
这种写法是因为在C#中处理动态类型转换时需要特别小心,尤其是在处理集合类型时。

  • 首先,shared 是一个 Dictionary,这意味着存储在其中的值都是 object 类型。
  • shared["evaluations"] 实际上存储的是一个列表,但由于存在字典中时是 object 类型,我们需要安全地将其转换回实际的类型。
  • 代码使用了两步转换的原因是:


  • 第一步:var objectList = shared["evaluations"] as List

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册