Agent设计模式学习(基于langchain4j实现)(4) - 并行工作流
<p>书接上回,现在简历已经润色得足够好了,投递到了HR手上,假设跟候选人也做了初步的电话沟通。接下来,公司需要对候选人做如下审查:</p><ul>
<li>经理:针对简历,结合招聘岗位要求,审查简历是否符合要求(包括优点和不足)</li>
<li>HR:针对简历,结合电话沟通记录以及HR招聘相关要求,审查简历是否适合(包括优点和不足)</li>
<li>团队成员:针对简历,评估候选人融入团队的程度(包括优点和不足)</li>
</ul>
<p>可以发现,这3个角色对候选人的评估,相互之间并无严格的顺序依赖,可以并行处理,这就是今天要说的“<span style="color: rgba(255, 0, 0, 1)">并行工作流</span>”,示意图如下:</p>
<p><img src="https://img2024.cnblogs.com/blog/27612/202601/27612-20260115185819908-1420895980.png" alt="image" width="480" loading="lazy" style="border: 1px solid rgba(0, 0, 0, 1)"></p>
<p> <span style="color: rgba(255, 0, 0, 1)">一、输入素材</span></p>
<p><span style="color: rgba(255, 0, 0, 1)">1.1</span> 人事招聘要求 hr_requirements.txt</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">## HR招聘要求
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> -<span style="color: rgba(0, 0, 0, 1)"> 姓名和联系方式必须清晰完整。
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> - 必须在比利时/<span style="color: rgba(0, 0, 0, 1)">欧盟有合法工作许可。
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> - 最好能在1-<span style="color: rgba(0, 0, 0, 1)">2个月内入职。
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> - 薪资期望在55,<span style="color: rgba(128, 0, 128, 1)">000</span>-<span style="color: rgba(128, 0, 128, 1)">70</span>,000欧元/<span style="color: rgba(0, 0, 0, 1)">年范围内。
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> -<span style="color: rgba(0, 0, 0, 1)"> 稳定的工作历史;无超过6个月的职业空白期。
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> -<span style="color: rgba(0, 0, 0, 1)"> 每个职位至少任职1年,且具有相关科技行业经验。
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> -<span style="color: rgba(0, 0, 0, 1)"> 职业生涯中职责范围的增长是可取的。
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> -<span style="color: rgba(0, 0, 0, 1)"> 要求荷兰语(母语水平)和英语(C1等级)流利。
</span><span style="color: rgba(0, 128, 128, 1)">10</span> -<span style="color: rgba(0, 0, 0, 1)"> 简历需清晰、专业;无重大语法问题。
</span><span style="color: rgba(0, 128, 128, 1)">11</span> - 具备团队合作、指导他人和产品导向经验者优先。</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">1.2</span> 电话面试记录 phone_interview_notes.txt</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> 电话面试记录 – 约翰·多伊 (后端工程师) – <span style="color: rgba(128, 0, 128, 1)">2025</span>-<span style="color: rgba(128, 0, 128, 1)">09</span>-<span style="color: rgba(128, 0, 128, 1)">05</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">面试官:萨拉·雅各布斯 (HR)
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">工作许可: 比利时公民;拥有欧盟工作许可。
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">工作地点: 安特卫普;倾向每周3天远程办公。
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">可入职时间: 需提前3个月通知;无需搬迁。
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">薪资期望: 当前年薪62,000欧元;期望约75,000欧元;要求培训预算。
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">工作经验: 约4年后端开发(Java, Spring Boot, PostgreSQL);领导过定价工具项目;使用过Kafka POC;对指导他人有兴趣。
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">职业履历: 当前职位4年,先前职位1.5年;无重大职业空白期。
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">软技能: 荷兰语母语,英语C1水平;沟通清晰;务实,产品导向。
</span><span style="color: rgba(0, 128, 128, 1)">11</span> 备注: 薪资略高于范围;可入职时间晚于预期;分布式系统经验有限。</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">1.3</span> 优化后的简历 tailored_cv.txt</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">约翰·多伊 – 后端工程师
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> 安特卫普,比利时 | john.doe.dev@protonmail.com | +<span style="color: rgba(128, 0, 128, 1)">32</span> <span style="color: rgba(128, 0, 128, 1)">495</span> <span style="color: rgba(128, 0, 128, 1)">67</span> <span style="color: rgba(128, 0, 128, 1)">89</span> <span style="color: rgba(128, 0, 128, 1)">23</span> | 领英 |<span style="color: rgba(0, 0, 0, 1)"> GitHub
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">简介
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">拥有4年以上经验的后端工程师(Java, Spring Boot, PostgreSQL),专注于可扩展系统、API现代化和自动化。荷兰语流利,英语C1水平。
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">工作经历
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> BrightPay Systems(2021年至今):构建后端服务;开发定价工具(报价时间缩短35%<span style="color: rgba(0, 0, 0, 1)">);完成SOAP到REST的API迁移;指导实习生。
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> CodeWave Solutions(<span style="color: rgba(128, 0, 128, 1)">2019</span>–2021年):后端开发;建立CI/CD流程(GitHub Actions);使用Docker、Kafka(概念验证);开发小型React管理界面;参与个人项目(Spring+<span style="color: rgba(0, 0, 0, 1)">Vue预算应用,物联网自动化)。
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">教育背景
</span><span style="color: rgba(0, 128, 128, 1)">12</span> Java 编程训练营,BeCode(<span style="color: rgba(128, 0, 128, 1)">2019</span><span style="color: rgba(0, 0, 0, 1)">–2020年)
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">机械工程学士,鲁汶大学(2016年)
</span><span style="color: rgba(0, 128, 128, 1)">14</span>
<span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">技能
</span><span style="color: rgba(0, 128, 128, 1)">16</span> 技术:Java,Spring Boot,PostgreSQL,Docker,Kafka(基础),CI/<span style="color: rgba(0, 0, 0, 1)">CD,REST设计,整洁代码,指导新人
</span><span style="color: rgba(0, 128, 128, 1)">17</span> 语言:荷兰语(母语),英语(C1),法语(B1)</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">二、定义各种审查Agent</span></p>
<p><span style="color: rgba(255, 0, 0, 1)">2.1 </span>HrCvReviewer </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> HrCvReviewer {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> @Agent(name = "hrReviewer", description = "审查简历以评估候选人是否符合HR要求,提供反馈和评分"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> @SystemMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)"> 你作为HR专员,根据以下职位要求审查简历:
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)"> {{hrRequirements}}
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)"> 你需要为每份简历提供评分和反馈(包括优点和不足之处)。
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)"> 可以忽略诸如缺少地址或占位符等内容。
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)"> 重要提示:请仅返回有效的JSON格式响应,换行符使用\\n,不要包含任何Markdown格式或代码块。
</span><span style="color: rgba(0, 128, 128, 1)">11</span> """)
<span style="color: rgba(0, 128, 128, 1)">12</span> @UserMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)"> 请审查这份简历:{{candidateCv}},以及附带的电话面试记录:{{phoneInterviewNotes}}
</span><span style="color: rgba(0, 128, 128, 1)">14</span> """)
<span style="color: rgba(0, 128, 128, 1)">15</span> CvReview reviewCv(@V("candidateCv") String cv, @V("phoneInterviewNotes") String phoneInterviewNotes, @V("hrRequirements"<span style="color: rgba(0, 0, 0, 1)">) String hrRequirements);
</span><span style="color: rgba(0, 128, 128, 1)">16</span> }</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">2.2</span> ManagerCvReviewer</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> ManagerCvReviewer {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> @Agent(name = "managerReviewer", description = "基于职位描述审查简历,提供反馈和评分"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> @SystemMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)"> 你是该职位的招聘经理:
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)"> {{jobDescription}}
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)"> 你需要审查申请人简历,从众多候选人中决定邀请谁参加现场面试。
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)"> 你需要为每份简历提供评分和反馈(包括优点和不足之处)。
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)"> 可以忽略诸如缺少地址或占位符等内容。
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)"> 重要提示:请仅返回有效的JSON格式响应,换行符使用\\n,不要包含任何Markdown格式或代码块。
</span><span style="color: rgba(0, 128, 128, 1)">12</span> """)
<span style="color: rgba(0, 128, 128, 1)">13</span> @UserMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)"> 请审查这份简历:{{candidateCv}}
</span><span style="color: rgba(0, 128, 128, 1)">15</span> """)
<span style="color: rgba(0, 128, 128, 1)">16</span> CvReview reviewCv(@V("candidateCv") String cv, @V("jobDescription"<span style="color: rgba(0, 0, 0, 1)">) String jobDescription);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> }</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">2.3</span> TeamMemberCvReviewer </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> TeamMemberCvReviewer {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> @Agent(name = "teamMemberReviewer", description = "审查简历以评估候选人是否适合团队,提供反馈和评分"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> @SystemMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)"> 你在一个充满动力、自我驱动的同事且拥有高度自由度的团队中工作。
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)"> 你的团队重视协作、责任感和务实精神。
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)"> 你需要审查申请人简历,评估此人融入团队的程度。
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)"> 你需要为每份简历提供评分和反馈(包括优点和不足之处)。
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)"> 可以忽略诸如缺少地址或占位符等内容。
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)"> 重要提示:请仅返回有效的JSON格式响应,换行符使用\\n,不要包含任何Markdown格式或代码块。
</span><span style="color: rgba(0, 128, 128, 1)">12</span> """)
<span style="color: rgba(0, 128, 128, 1)">13</span> @UserMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)"> 请审查这份简历:{{candidateCv}}
</span><span style="color: rgba(0, 128, 128, 1)">15</span> """)
<span style="color: rgba(0, 128, 128, 1)">16</span> CvReview reviewCv(@V("candidateCv"<span style="color: rgba(0, 0, 0, 1)">) String cv);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> }</pre>
</div>
<p> 三、并行Agent示例</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 128, 0, 1)">/**</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 128, 0, 1)"> * 这个示例演示了如何实现3个并行的CvReviewer智能体,
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 128, 0, 1)"> * 它们将同时评估简历。我们将实现三个智能体:
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 128, 0, 1)"> * - ManagerCvReviewer(评估候选人胜任工作的可能性)
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 128, 0, 1)"> * 输入:简历和职位描述
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 128, 0, 1)"> * - TeamMemberCvReviewer(评估候选人融入团队的程度)
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 128, 0, 1)"> * 输入:简历
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 128, 0, 1)"> * - HrCvReviewer(从HR角度检查候选人是否符合要求)
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 128, 0, 1)"> * 输入:简历、HR要求
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 128, 0, 1)"> * by 菩提树下的杨过(yjmyzz.cnblogs.com)
</span><span style="color: rgba(0, 128, 128, 1)">11</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">@SpringBootApplication
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> _4_Parallel_Workflow_Example {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>
<span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
</span><span style="color: rgba(0, 128, 128, 1)">16</span> ConfigurableApplicationContext context = SpringApplication.run(AgentDesignPatternApplication.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> ChatModel model = context.getBean("ollamaChatModel", ChatModel.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">18</span>
<span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 2. 在本包中定义三个子智能体:
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> - HrCvReviewer.java
</span><span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> - ManagerCvReviewer.java
</span><span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> - TeamMemberCvReviewer.java
</span><span style="color: rgba(0, 128, 128, 1)">23</span>
<span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 3. 使用AgenticServices创建所有智能体</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> HrCvReviewer hrCvReviewer = AgenticServices.agentBuilder(HrCvReviewer.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)"> .chatModel(model)
</span><span style="color: rgba(0, 128, 128, 1)">27</span> .outputKey("hrReview") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这将在每次迭代中被覆盖,同时也作为我们想要观察的最终输出</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</span><span style="color: rgba(0, 128, 128, 1)">29</span>
<span style="color: rgba(0, 128, 128, 1)">30</span> ManagerCvReviewer managerCvReviewer = AgenticServices.agentBuilder(ManagerCvReviewer.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(0, 0, 0, 1)"> .chatModel(model)
</span><span style="color: rgba(0, 128, 128, 1)">32</span> .outputKey("managerReview") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这会覆盖原始输入指令,并在每次迭代中被覆盖,用作CvTailor的新指令</span>
<span style="color: rgba(0, 128, 128, 1)">33</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</span><span style="color: rgba(0, 128, 128, 1)">34</span>
<span style="color: rgba(0, 128, 128, 1)">35</span> TeamMemberCvReviewer teamMemberCvReviewer = AgenticServices.agentBuilder(TeamMemberCvReviewer.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">36</span> <span style="color: rgba(0, 0, 0, 1)"> .chatModel(model)
</span><span style="color: rgba(0, 128, 128, 1)">37</span> .outputKey("teamMemberReview") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这会覆盖原始输入指令,并在每次迭代中被覆盖,用作CvTailor的新指令</span>
<span style="color: rgba(0, 128, 128, 1)">38</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</span><span style="color: rgba(0, 128, 128, 1)">39</span>
<span style="color: rgba(0, 128, 128, 1)">40</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 4. 构建执行流程</span>
<span style="color: rgba(0, 128, 128, 1)">41</span> var executor = Executors.newFixedThreadPool(3);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 保留引用以便后续关闭</span>
<span style="color: rgba(0, 128, 128, 1)">42</span>
<span style="color: rgba(0, 128, 128, 1)">43</span> UntypedAgent cvReviewGenerator = AgenticServices <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用UntypedAgent,除非你定义了结果组合智能体,参见_2_Sequential_Agent_Example</span>
<span style="color: rgba(0, 128, 128, 1)">44</span> <span style="color: rgba(0, 0, 0, 1)"> .parallelBuilder()
</span><span style="color: rgba(0, 128, 128, 1)">45</span> .subAgents(hrCvReviewer, managerCvReviewer, teamMemberCvReviewer) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 可以添加任意多个</span>
<span style="color: rgba(0, 128, 128, 1)">46</span> .executor(executor) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 可选,默认使用内部缓存的线程池,执行完成后会自动关闭</span>
<span style="color: rgba(0, 128, 128, 1)">47</span> .outputKey("fullCvReview") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这是我们想要观察的最终输出</span>
<span style="color: rgba(0, 128, 128, 1)">48</span> .output(agenticScope -><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">49</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 从智能体作用域读取每个评审者的输出</span>
<span style="color: rgba(0, 128, 128, 1)">50</span> CvReview hrReview = (CvReview) agenticScope.readState("hrReview"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">51</span> CvReview managerReview = (CvReview) agenticScope.readState("managerReview"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">52</span> CvReview teamMemberReview = (CvReview) agenticScope.readState("teamMemberReview"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">53</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回汇总的评审结果,包含平均分(或你想要的任何其他聚合方式)</span>
<span style="color: rgba(0, 128, 128, 1)">54</span> String feedback = String.join("\n"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">55</span> "HR评审: " +<span style="color: rgba(0, 0, 0, 1)"> hrReview.feedback,
</span><span style="color: rgba(0, 128, 128, 1)">56</span> "经理评审: " +<span style="color: rgba(0, 0, 0, 1)"> managerReview.feedback,
</span><span style="color: rgba(0, 128, 128, 1)">57</span> "团队成员评审: " +<span style="color: rgba(0, 0, 0, 1)"> teamMemberReview.feedback
</span><span style="color: rgba(0, 128, 128, 1)">58</span> <span style="color: rgba(0, 0, 0, 1)"> );
</span><span style="color: rgba(0, 128, 128, 1)">59</span> <span style="color: rgba(0, 0, 255, 1)">double</span> avgScore = (hrReview.score + managerReview.score + teamMemberReview.score) / 3.0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">60</span>
<span style="color: rgba(0, 128, 128, 1)">61</span> <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> CvReview(avgScore, feedback);
</span><span style="color: rgba(0, 128, 128, 1)">62</span> <span style="color: rgba(0, 0, 0, 1)"> })
</span><span style="color: rgba(0, 128, 128, 1)">63</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</span><span style="color: rgba(0, 128, 128, 1)">64</span>
<span style="color: rgba(0, 128, 128, 1)">65</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 5. 从resources/documents/目录下的文本文件加载原始参数</span>
<span style="color: rgba(0, 128, 128, 1)">66</span> String candidateCv = StringLoader.loadFromResource("/documents/tailored_cv.txt"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">67</span> String jobDescription = StringLoader.loadFromResource("/documents/job_description_backend.txt"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">68</span> String hrRequirements = StringLoader.loadFromResource("/documents/hr_requirements.txt"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">69</span> String phoneInterviewNotes = StringLoader.loadFromResource("/documents/phone_interview_notes.txt"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">70</span>
<span style="color: rgba(0, 128, 128, 1)">71</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 6. 由于我们使用了无类型智能体,需要传递参数映射</span>
<span style="color: rgba(0, 128, 128, 1)">72</span> Map<String, Object> arguments =<span style="color: rgba(0, 0, 0, 1)"> Map.of(
</span><span style="color: rgba(0, 128, 128, 1)">73</span> "candidateCv"<span style="color: rgba(0, 0, 0, 1)">, candidateCv,
</span><span style="color: rgba(0, 128, 128, 1)">74</span> "jobDescription"<span style="color: rgba(0, 0, 0, 1)">, jobDescription
</span><span style="color: rgba(0, 128, 128, 1)">75</span> , "hrRequirements"<span style="color: rgba(0, 0, 0, 1)">, hrRequirements
</span><span style="color: rgba(0, 128, 128, 1)">76</span> , "phoneInterviewNotes"<span style="color: rgba(0, 0, 0, 1)">, phoneInterviewNotes
</span><span style="color: rgba(0, 128, 128, 1)">77</span> <span style="color: rgba(0, 0, 0, 1)"> );
</span><span style="color: rgba(0, 128, 128, 1)">78</span>
<span style="color: rgba(0, 128, 128, 1)">79</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 7. 调用组合智能体生成定制的简历</span>
<span style="color: rgba(0, 128, 128, 1)">80</span> var review =<span style="color: rgba(0, 0, 0, 1)"> cvReviewGenerator.invoke(arguments);
</span><span style="color: rgba(0, 128, 128, 1)">81</span>
<span style="color: rgba(0, 128, 128, 1)">82</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 8. 打印生成的简历</span>
<span style="color: rgba(0, 128, 128, 1)">83</span> System.out.println("=== 已评审的简历 ==="<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">84</span> <span style="color: rgba(0, 0, 0, 1)"> System.out.println(review);
</span><span style="color: rgba(0, 128, 128, 1)">85</span>
<span style="color: rgba(0, 128, 128, 1)">86</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 9. 关闭执行器</span>
<span style="color: rgba(0, 128, 128, 1)">87</span> <span style="color: rgba(0, 0, 0, 1)"> executor.shutdown();
</span><span style="color: rgba(0, 128, 128, 1)">88</span>
<span style="color: rgba(0, 128, 128, 1)">89</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">90</span>
<span style="color: rgba(0, 128, 128, 1)">91</span>
<span style="color: rgba(0, 128, 128, 1)">92</span> }</pre>
</div>
<p>时序图(简化版) - AI生成</p>
<p><img src="https://img2024.cnblogs.com/blog/27612/202601/27612-20260117155111713-313918219.png" alt="04_sequence_diagram_simple" width="480" loading="lazy" style="border: 1px solid rgba(0, 0, 0, 1)"></p>
<p>时序图(详细版) - AI生成</p>
<p><img src="https://img2024.cnblogs.com/blog/27612/202601/27612-20260117155130833-60883978.png" alt="04_sequence_diagram_detail" width="480" loading="lazy" style="border: 1px solid rgba(0, 0, 0, 1)"></p>
<p> 运行结果:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(128, 0, 128, 1)">2026</span>-<span style="color: rgba(128, 0, 128, 1)">01</span>-17T15:<span style="color: rgba(128, 0, 128, 1)">54</span>:<span style="color: rgba(128, 0, 128, 1)">11.422</span>+<span style="color: rgba(128, 0, 128, 1)">08</span>:<span style="color: rgba(128, 0, 128, 1)">00</span>INFO <span style="color: rgba(128, 0, 128, 1)">9072</span> --- d.l.http.client.log.LoggingHttpClient : HTTP request:
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> -<span style="color: rgba(0, 0, 0, 1)"> method: POST
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> - url: http:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">localhost:11434/api/chat</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> - headers:
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> -<span style="color: rgba(0, 0, 0, 1)"> body: {
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">model</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b-cloud</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">messages</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">system</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你在一个充满动力、自我驱动的同事且拥有高度自由度的团队中工作。\n你的团队重视协作、责任感和务实精神。\n你需要审查申请人简历,评估此人融入团队的程度。\n你需要为每份简历提供评分和反馈(包括优点和不足之处)。\n可以忽略诸如缺少地址或占位符等内容。\n\n重要提示:请仅返回有效的JSON格式响应,换行符使用\\n,不要包含任何Markdown格式或代码块。\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">}, {
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">请审查这份简历:约翰·多伊 – 后端工程师\r\n安特卫普,比利时 | john.doe.dev@protonmail.com | +32 495 67 89 23 | 领英 | GitHub\r\n\r\n简介\r\n拥有4年以上经验的后端工程师(Java, Spring Boot, PostgreSQL),专注于可扩展系统、API现代化和自动化。荷兰语流利,英语C1水平。\r\n\r\n工作经历\r\nBrightPay Systems(2021年至今):构建后端服务;开发定价工具(报价时间缩短35%);完成SOAP到REST的API迁移;指导实习生。\r\nCodeWave Solutions(2019–2021年):后端开发;建立CI/CD流程(GitHub Actions);使用Docker、Kafka(概念验证);开发小型React管理界面;参与个人项目(Spring+Vue预算应用,物联网自动化)。\r\n\r\n教育背景\r\nJava 编程训练营,BeCode(2019–2020年)\r\n机械工程学士,鲁汶大学(2016年)\r\n\r\n技能\r\n技术:Java,Spring Boot,PostgreSQL,Docker,Kafka(基础),CI/CD,REST设计,整洁代码,指导新人\r\n语言:荷兰语(母语),英语(C1),法语(B1)\n\nYou must answer strictly in the following JSON format: {\n\"score\": (从0到1分你邀请这位应聘者参加面试的可能性; type: double),\n\"feedback\": (对简历的反馈,什么是好的,什么需要改进,什么技能缺失,什么危险信号……; type: string)\n}</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">} ],
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">options</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : {
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stop</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ ]
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stream</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tools</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ ]
</span><span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">20</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(128, 0, 128, 1)">2026</span>-<span style="color: rgba(128, 0, 128, 1)">01</span>-17T15:<span style="color: rgba(128, 0, 128, 1)">54</span>:<span style="color: rgba(128, 0, 128, 1)">11.422</span>+<span style="color: rgba(128, 0, 128, 1)">08</span>:<span style="color: rgba(128, 0, 128, 1)">00</span>INFO <span style="color: rgba(128, 0, 128, 1)">9072</span> --- d.l.http.client.log.LoggingHttpClient : HTTP request:
</span><span style="color: rgba(0, 128, 128, 1)">22</span> -<span style="color: rgba(0, 0, 0, 1)"> method: POST
</span><span style="color: rgba(0, 128, 128, 1)">23</span> - url: http:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">localhost:11434/api/chat</span>
<span style="color: rgba(0, 128, 128, 1)">24</span> - headers:
</span><span style="color: rgba(0, 128, 128, 1)">25</span> -<span style="color: rgba(0, 0, 0, 1)"> body: {
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">model</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b-cloud</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">messages</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ {
</span><span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">system</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你是该职位的招聘经理:\n职位描述 ID: 123A\r\n后端工程师(金融科技,安特卫普)\r\n------------------------------------------------------------\r\n我们正在招聘一位**后端工程师**,协助我们构建并完善支付与对账服务。您将主要使用 **Java (Spring Boot)**,并与产品及运营团队紧密合作,确保金融交易系统的可靠性和可扩展性。\r\n\r\n**职责:**\r\n* 设计、实现并维护能够处理大规模支付与对账业务的后端服务。\r\n* 在云原生环境中使用 **PostgreSQL**、**Kafka**、**Docker** 和 **Kubernetes**。\r\n* 专注于构建可靠、幂等的系统,并具备强大的可观测性。\r\n* 支持将遗留服务迁移至现代的 REST API。\r\n\r\n**要求:**\r\n* 具备 Java 和 Spring Boot 后端开发的职业经验。\r\n* 深入理解关系型数据库和事件驱动架构。\r\n* 熟悉容器化技术和部署流程。\r\n* 有金融或定价系统相关经验者优先。\r\n* 要求英语流利,会荷兰语者更佳。\n你需要审查申请人简历,从众多候选人中决定邀请谁参加现场面试。\n你需要为每份简历提供评分和反馈(包括优点和不足之处)。\n可以忽略诸如缺少地址或占位符等内容。\n\n重要提示:请仅返回有效的JSON格式响应,换行符使用\\n,不要包含任何Markdown格式或代码块。\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">30</span> <span style="color: rgba(0, 0, 0, 1)">}, {
</span><span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">32</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">请审查这份简历:约翰·多伊 – 后端工程师\r\n安特卫普,比利时 | john.doe.dev@protonmail.com | +32 495 67 89 23 | 领英 | GitHub\r\n\r\n简介\r\n拥有4年以上经验的后端工程师(Java, Spring Boot, PostgreSQL),专注于可扩展系统、API现代化和自动化。荷兰语流利,英语C1水平。\r\n\r\n工作经历\r\nBrightPay Systems(2021年至今):构建后端服务;开发定价工具(报价时间缩短35%);完成SOAP到REST的API迁移;指导实习生。\r\nCodeWave Solutions(2019–2021年):后端开发;建立CI/CD流程(GitHub Actions);使用Docker、Kafka(概念验证);开发小型React管理界面;参与个人项目(Spring+Vue预算应用,物联网自动化)。\r\n\r\n教育背景\r\nJava 编程训练营,BeCode(2019–2020年)\r\n机械工程学士,鲁汶大学(2016年)\r\n\r\n技能\r\n技术:Java,Spring Boot,PostgreSQL,Docker,Kafka(基础),CI/CD,REST设计,整洁代码,指导新人\r\n语言:荷兰语(母语),英语(C1),法语(B1)\n\nYou must answer strictly in the following JSON format: {\n\"score\": (从0到1分你邀请这位应聘者参加面试的可能性; type: double),\n\"feedback\": (对简历的反馈,什么是好的,什么需要改进,什么技能缺失,什么危险信号……; type: string)\n}</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">33</span> <span style="color: rgba(0, 0, 0, 1)">} ],
</span><span style="color: rgba(0, 128, 128, 1)">34</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">options</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : {
</span><span style="color: rgba(0, 128, 128, 1)">35</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stop</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ ]
</span><span style="color: rgba(0, 128, 128, 1)">36</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)">37</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stream</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">38</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tools</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ ]
</span><span style="color: rgba(0, 128, 128, 1)">39</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">40</span>
<span style="color: rgba(0, 128, 128, 1)">41</span> <span style="color: rgba(128, 0, 128, 1)">2026</span>-<span style="color: rgba(128, 0, 128, 1)">01</span>-17T15:<span style="color: rgba(128, 0, 128, 1)">54</span>:<span style="color: rgba(128, 0, 128, 1)">11.422</span>+<span style="color: rgba(128, 0, 128, 1)">08</span>:<span style="color: rgba(128, 0, 128, 1)">00</span>INFO <span style="color: rgba(128, 0, 128, 1)">9072</span> --- d.l.http.client.log.LoggingHttpClient : HTTP request:
</span><span style="color: rgba(0, 128, 128, 1)">42</span> -<span style="color: rgba(0, 0, 0, 1)"> method: POST
</span><span style="color: rgba(0, 128, 128, 1)">43</span> - url: http:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">localhost:11434/api/chat</span>
<span style="color: rgba(0, 128, 128, 1)">44</span> - headers:
</span><span style="color: rgba(0, 128, 128, 1)">45</span> -<span style="color: rgba(0, 0, 0, 1)"> body: {
</span><span style="color: rgba(0, 128, 128, 1)">46</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">model</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b-cloud</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">47</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">messages</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ {
</span><span style="color: rgba(0, 128, 128, 1)">48</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">system</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">49</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你作为HR专员,根据以下职位要求审查简历:\n## HR招聘要求\r\n- 姓名和联系方式必须清晰完整。\r\n- 必须在比利时/欧盟有合法工作许可。\r\n- 最好能在1-2个月内入职。\r\n- 薪资期望在55,000-70,000欧元/年范围内。\r\n- 稳定的工作历史;无超过6个月的职业空白期。\r\n- 每个职位至少任职1年,且具有相关科技行业经验。\r\n- 职业生涯中职责范围的增长是可取的。\r\n- 要求荷兰语(母语水平)和英语(C1等级)流利。\r\n- 简历需清晰、专业;无重大语法问题。\r\n- 具备团队合作、指导他人和产品导向经验者优先。\n你需要为每份简历提供评分和反馈(包括优点和不足之处)。\n可以忽略诸如缺少地址或占位符等内容。\n\n重要提示:请仅返回有效的JSON格式响应,换行符使用\\n,不要包含任何Markdown格式或代码块。\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">50</span> <span style="color: rgba(0, 0, 0, 1)">}, {
</span><span style="color: rgba(0, 128, 128, 1)">51</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">52</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">请审查这份简历:约翰·多伊 – 后端工程师\r\n安特卫普,比利时 | john.doe.dev@protonmail.com | +32 495 67 89 23 | 领英 | GitHub\r\n\r\n简介\r\n拥有4年以上经验的后端工程师(Java, Spring Boot, PostgreSQL),专注于可扩展系统、API现代化和自动化。荷兰语流利,英语C1水平。\r\n\r\n工作经历\r\nBrightPay Systems(2021年至今):构建后端服务;开发定价工具(报价时间缩短35%);完成SOAP到REST的API迁移;指导实习生。\r\nCodeWave Solutions(2019–2021年):后端开发;建立CI/CD流程(GitHub Actions);使用Docker、Kafka(概念验证);开发小型React管理界面;参与个人项目(Spring+Vue预算应用,物联网自动化)。\r\n\r\n教育背景\r\nJava 编程训练营,BeCode(2019–2020年)\r\n机械工程学士,鲁汶大学(2016年)\r\n\r\n技能\r\n技术:Java,Spring Boot,PostgreSQL,Docker,Kafka(基础),CI/CD,REST设计,整洁代码,指导新人\r\n语言:荷兰语(母语),英语(C1),法语(B1),以及附带的电话面试记录:电话面试记录 – 约翰·多伊 (后端工程师) – 2025-09-05\r\n面试官:萨拉·雅各布斯 (HR)\r\n\r\n工作许可: 比利时公民;拥有欧盟工作许可。\r\n工作地点: 安特卫普;倾向每周3天远程办公。\r\n可入职时间: 需提前3个月通知;无需搬迁。\r\n薪资期望: 当前年薪62,000欧元;期望约75,000欧元;要求培训预算。\r\n工作经验: 约4年后端开发(Java, Spring Boot, PostgreSQL);领导过定价工具项目;使用过Kafka POC;对指导他人有兴趣。\r\n职业履历: 当前职位4年,先前职位1.5年;无重大职业空白期。\r\n软技能: 荷兰语母语,英语C1水平;沟通清晰;务实,产品导向。\r\n备注: 薪资略高于范围;可入职时间晚于预期;分布式系统经验有限。\n\nYou must answer strictly in the following JSON format: {\n\"score\": (从0到1分你邀请这位应聘者参加面试的可能性; type: double),\n\"feedback\": (对简历的反馈,什么是好的,什么需要改进,什么技能缺失,什么危险信号……; type: string)\n}</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">53</span> <span style="color: rgba(0, 0, 0, 1)">} ],
</span><span style="color: rgba(0, 128, 128, 1)">54</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">options</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : {
</span><span style="color: rgba(0, 128, 128, 1)">55</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stop</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ ]
</span><span style="color: rgba(0, 128, 128, 1)">56</span> <span style="color: rgba(0, 0, 0, 1)">},
</span><span style="color: rgba(0, 128, 128, 1)">57</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stream</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">58</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tools</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : [ ]
</span><span style="color: rgba(0, 128, 128, 1)">59</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">60</span>
<span style="color: rgba(0, 128, 128, 1)">61</span> <span style="color: rgba(128, 0, 128, 1)">2026</span>-<span style="color: rgba(128, 0, 128, 1)">01</span>-17T15:<span style="color: rgba(128, 0, 128, 1)">54</span>:<span style="color: rgba(128, 0, 128, 1)">14.452</span>+<span style="color: rgba(128, 0, 128, 1)">08</span>:<span style="color: rgba(128, 0, 128, 1)">00</span>INFO <span style="color: rgba(128, 0, 128, 1)">9072</span> --- d.l.http.client.log.LoggingHttpClient : HTTP response:
</span><span style="color: rgba(0, 128, 128, 1)">62</span> - status code: <span style="color: rgba(128, 0, 128, 1)">200</span>
<span style="color: rgba(0, 128, 128, 1)">63</span> - headers: , [<span style="color: rgba(0, 0, 255, 1)">date</span>: Sat, <span style="color: rgba(128, 0, 128, 1)">17</span> Jan <span style="color: rgba(128, 0, 128, 1)">2026</span> <span style="color: rgba(128, 0, 128, 1)">07</span>:<span style="color: rgba(128, 0, 128, 1)">54</span>:<span style="color: rgba(128, 0, 128, 1)">14</span> GMT],
</span><span style="color: rgba(0, 128, 128, 1)">64</span> - body: {<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">model</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b-cloud</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">remote_model</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">remote_host</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://ollama.com:443</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">created_at</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2026-01-17T07:54:14.128982804Z</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">message</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">assistant</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{\n\"score\": 0.7,\n\"feedback\": \"优点:拥有4年相关的Java和Spring Boot经验,具体参与了API现代化工作(SOAP到REST),符合职位需求。有定价工具开发经验,这是优先考虑项。技术栈(PostgreSQL, Docker)与职位匹配。荷兰语流利,英语沟通能力良好。有指导经验。\\n不足之处:金融科技或支付系统直接经验未明确提及,这是一个关键需求。Kafka经验标注为“基础”和“概念验证”,可能不够深入。金融系统所需的可靠性和可观测性技能在简历中未突出。缺乏Kubernetes经验的明确说明。教育背景中机械工程学位与软件工程关联性较弱。\"\n}</span><span style="color: rgba(128, 0, 0, 1)">"</span>},<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">done</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(0, 0, 255, 1)">true</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">done_reason</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stop</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">total_duration</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">2523983598</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">prompt_eval_count</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">674</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">eval_count</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">153</span><span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">65</span>
<span style="color: rgba(0, 128, 128, 1)">66</span>
<span style="color: rgba(0, 128, 128, 1)">67</span> <span style="color: rgba(128, 0, 128, 1)">2026</span>-<span style="color: rgba(128, 0, 128, 1)">01</span>-17T15:<span style="color: rgba(128, 0, 128, 1)">55</span>:<span style="color: rgba(128, 0, 128, 1)">22.847</span>+<span style="color: rgba(128, 0, 128, 1)">08</span>:<span style="color: rgba(128, 0, 128, 1)">00</span>INFO <span style="color: rgba(128, 0, 128, 1)">9072</span> --- d.l.http.client.log.LoggingHttpClient : HTTP response:
</span><span style="color: rgba(0, 128, 128, 1)">68</span> - status code: <span style="color: rgba(128, 0, 128, 1)">200</span>
<span style="color: rgba(0, 128, 128, 1)">69</span> - headers: , [<span style="color: rgba(0, 0, 255, 1)">date</span>: Sat, <span style="color: rgba(128, 0, 128, 1)">17</span> Jan <span style="color: rgba(128, 0, 128, 1)">2026</span> <span style="color: rgba(128, 0, 128, 1)">07</span>:<span style="color: rgba(128, 0, 128, 1)">55</span>:<span style="color: rgba(128, 0, 128, 1)">22</span> GMT],
</span><span style="color: rgba(0, 128, 128, 1)">70</span> - body: {<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">model</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b-cloud</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">remote_model</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">remote_host</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://ollama.com:443</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">created_at</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2026-01-17T07:55:22.545191436Z</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">message</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">assistant</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{\n\"score\": 0.75,\n\"feedback\": \"好的方面:具备4年相关经验,技术栈与职位需求匹配(Java, Spring Boot, PostgreSQL),有实际项目成果(如SOAP到REST迁移、CI/CD实施),显示了自动化和可扩展系统的关注点;拥有指导经验,符合团队协作价值观。需要改进:个人项目和技术广度(如Kafka基础、React经验)可能不太深入,缺乏对系统设计或大规模处理的具体细节;教育背景中机械工程与软件工程无关,但训练营弥补了部分。技能缺失:缺乏云平台(AWS/Azure)或微服务架构经验,可能限制在高度分布式团队中的贡献。无明显危险信号。\"\n}</span><span style="color: rgba(128, 0, 0, 1)">"</span>},<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">done</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(0, 0, 255, 1)">true</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">done_reason</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stop</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">total_duration</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">10361972956</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">prompt_eval_count</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">442</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">eval_count</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">151</span><span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">71</span>
<span style="color: rgba(0, 128, 128, 1)">72</span>
<span style="color: rgba(0, 128, 128, 1)">73</span> <span style="color: rgba(128, 0, 128, 1)">2026</span>-<span style="color: rgba(128, 0, 128, 1)">01</span>-17T15:<span style="color: rgba(128, 0, 128, 1)">55</span>:<span style="color: rgba(128, 0, 128, 1)">26.421</span>+<span style="color: rgba(128, 0, 128, 1)">08</span>:<span style="color: rgba(128, 0, 128, 1)">00</span>INFO <span style="color: rgba(128, 0, 128, 1)">9072</span> --- d.l.http.client.log.LoggingHttpClient : HTTP response:
</span><span style="color: rgba(0, 128, 128, 1)">74</span> - status code: <span style="color: rgba(128, 0, 128, 1)">200</span>
<span style="color: rgba(0, 128, 128, 1)">75</span> - headers: , [<span style="color: rgba(0, 0, 255, 1)">date</span>: Sat, <span style="color: rgba(128, 0, 128, 1)">17</span> Jan <span style="color: rgba(128, 0, 128, 1)">2026</span> <span style="color: rgba(128, 0, 128, 1)">07</span>:<span style="color: rgba(128, 0, 128, 1)">55</span>:<span style="color: rgba(128, 0, 128, 1)">26</span> GMT],
</span><span style="color: rgba(0, 128, 128, 1)">76</span> - body: {<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">model</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b-cloud</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">remote_model</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">deepseek-v3.1:671b</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">remote_host</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://ollama.com:443</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">created_at</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2026-01-17T07:55:26.117462176Z</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">message</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">role</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">assistant</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{\n\"score\": 0.7,\n\"feedback\": \"简历优点:姓名、联系方式和比利时/欧盟工作许可明确;每个职位任职时间超过1年(分别是4年和1.5年),无重大职业空白期,工作历史稳定;荷兰语和英语水平符合要求(荷兰语母语,英语C1);技能与职位要求匹配,具有Java、Spring Boot等后端开发经验;展示了职责范围增长(如指导实习生、领导定价工具项目)。不足之处:薪资期望(75,000欧元)略高于职位范围(55,000-70,000欧元);可入职时间(需3个月通知)晚于理想的1-2个月;分布式系统经验(如Kafka)有限且为概念验证;简历过于简洁,缺乏细节,如工作职责描述可以更具体和专业。\"\n}</span><span style="color: rgba(128, 0, 0, 1)">"</span>},<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">done</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(0, 0, 255, 1)">true</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">done_reason</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stop</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">total_duration</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">13998598290</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">prompt_eval_count</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">798</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">eval_count</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 128, 1)">174</span><span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">77</span>
<span style="color: rgba(0, 128, 128, 1)">78</span>
<span style="color: rgba(0, 128, 128, 1)">79</span> === 已评审的简历 ===
<span style="color: rgba(0, 128, 128, 1)">80</span>
<span style="color: rgba(0, 128, 128, 1)">81</span> CvReview:- score = <span style="color: rgba(128, 0, 128, 1)">0.7166666666666667</span>
<span style="color: rgba(0, 128, 128, 1)">82</span> - feedback = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HR评审: 简历优点:姓名、联系方式和比利时/欧盟工作许可明确;每个职位任职时间超过1年(分别是4年和1.5年),无重大职业空白期,工作历史稳定;荷兰语和英语水平符合要求(荷兰语母语,英语C1);技能与职位要求匹配,具有Java、Spring Boot等后端开发经验;展示了职责范围增长(如指导实习生、领导定价工具项目)。不足之处:薪资期望(75,000欧元)略高于职位范围(55,000-70,000欧元);可入职时间(需3个月通知)晚于理想的1-2个月;分布式系统经验(如Kafka)有限且为概念验证;简历过于简洁,缺乏细节,如工作职责描述可以更具体和专业。</span>
<span style="color: rgba(0, 128, 128, 1)">83</span> <span style="color: rgba(0, 0, 0, 1)">经理评审: 优点:拥有4年相关的Java和Spring Boot经验,具体参与了API现代化工作(SOAP到REST),符合职位需求。有定价工具开发经验,这是优先考虑项。技术栈(PostgreSQL, Docker)与职位匹配。荷兰语流利,英语沟通能力良好。有指导经验。
</span><span style="color: rgba(0, 128, 128, 1)">84</span> <span style="color: rgba(0, 0, 0, 1)">不足之处:金融科技或支付系统直接经验未明确提及,这是一个关键需求。Kafka经验标注为“基础”和“概念验证”,可能不够深入。金融系统所需的可靠性和可观测性技能在简历中未突出。缺乏Kubernetes经验的明确说明。教育背景中机械工程学位与软件工程关联性较弱。
</span><span style="color: rgba(0, 128, 128, 1)">85</span> 团队成员评审: 好的方面:具备4年相关经验,技术栈与职位需求匹配(Java, Spring Boot, PostgreSQL),有实际项目成果(如SOAP到REST迁移、CI/CD实施),显示了自动化和可扩展系统的关注点;拥有指导经验,符合团队协作价值观。需要改进:个人项目和技术广度(如Kafka基础、React经验)可能不太深入,缺乏对系统设计或大规模处理的具体细节;教育背景中机械工程与软件工程无关,但训练营弥补了部分。技能缺失:缺乏云平台(AWS/Azure)或微服务架构经验,可能限制在高度分布式团队中的贡献。无明显危险信号。<span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<p>82行,即为3个评审Agent并行执行的结果。</p>
<p> </p>
<p>文中示例代码:</p>
<p>https://github.com/yjmyzz/agentic_turoial_with_langchain4j<br></p>
<p> </p>
<p>参考:</p>
<p>Building Effective AI Agents \ Anthropic</p>
<p>[译] AI Workflow & AI Agent:架构、模式与工程建议(Anthropic,2024)</p>
<p>Agents and Agentic AI | LangChain4j</p>
</div>
<div id="MySignature" role="contentinfo">
<div style="padding:5px;background:#ff9;border:solid 1px #ccc">作者:菩提树下的杨过<br />
出处:http://yjmyzz.cnblogs.com
<br/>
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
</div><br><br>
来源:https://www.cnblogs.com/yjmyzz/p/19488918/agentic-patterns-using-langchain4j-4-parallel-agent
頁:
[1]