Agent设计模式学习(基于langchain4j实现)(1) - 基础Agent用法
<p>自近年AI智能体火爆以来,各种相关的框架和最佳实践也不断涌现,Anthropic公司2024年发布的Building Effective AI Agents \ Anthropic 无疑是最有影响力的指导文章之一,langchain4j在此影响之下,也实现一系列的workflow编排&Agent功能。</p><p>本文将在langchain4j官方示例基础上(不熟悉langchain4j的朋友,请移步langchain4j学习系列),介绍几个主要模式的用法,今天先来看最基本的Agent如何实现</p>
<p>为方便讨论,先交待一下这一系列的<strong>业务背景</strong>:</p>
<ul>
<li>假设有1个公司要招聘,将利用Agent来实现简历生成(通过个人介绍)、简历筛选、简历优化 等一系列功能。</li>
<li>候选人的个人资料 user_life_stody.txt</li>
</ul>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">John Doe 现居比利时安特卫普(Rue des Carmes 12, 2000 Antwerp),联系方式为 john.doe.dev@protonmail.com 或 +32 495 67 89 23。他在 LinkedIn 和 GitHub 上保持活跃。
- 2020 年完成夜间 Java 集训营(2019–2020)后从机械工程领域转型至软件开发。
- 拥有 4 年软件开发经验,其中最近 2 年专注于 Java 后端开发(Spring Boot、PostgreSQL、Kafka 基础)。
- 开发了一款内部报价工具,将报价周转时间缩短约 35%。
- 领导 3 人专项小组,将遗留 SOAP 服务迁移至 REST 架构。
- 熟悉 Docker 与 CI 流水线(GitHub Actions)。
- 具备 React 使用经验,曾开发内部管理面板(非核心优势)。
- 重视代码整洁与可维护性,乐于指导实习生。
- 偏好产品开发而非外包项目;不喜冗长会议,注重交付实际价值。
- 语言:荷兰语(母语)、英语(C1)、法语(B1)。
- 教育背景:机械工程学士(2016 年),Java 集训营(2019–2020)。
- 个人项目包括一款小型预算管理应用(Spring + Vue)和一套家庭物联网系统(ESP32 + MQTT)。
</pre>
</div>
<p> </p>
<p><span style="color: rgba(255, 0, 0, 1)">一、定义Agent接口</span></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)"> CvGenerator {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> @UserMessage(<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> <span style="color: rgba(0, 0, 0, 1)"> 请将其整理成一份清晰、完整的简历。
</span><span style="color: rgba(0, 128, 128, 1)"> 5</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> 1<span style="color: rgba(0, 0, 0, 1)">. 不要编造任何事实
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> 2<span style="color: rgba(0, 0, 0, 1)">. 不要遗漏任何技能或经历
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> 3<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)"> 我的个人经历:{{lifeStory}}
</span><span style="color: rgba(0, 128, 128, 1)">12</span> """)
<span style="color: rgba(0, 128, 128, 1)">13</span> @Agent("基于用户提供的信息生成规范的简历"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">14</span> String generateCv(@V("lifeStory"<span style="color: rgba(0, 0, 0, 1)">) String userInfo);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> }</pre>
</div>
<p>这个正是langchain4j中的AiService,只不过这里我们使用了@Agent这个注解,需要添加下面的依赖</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>dev.langchain4j<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>langchain4j-agentic<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>1.10.0-beta18<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<p> </p>
<p><span style="color: rgba(255, 0, 0, 1)">二、最基础的Agent示例</span></p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_5bc047d5-a113-42a8-8151-d74808632c42" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_5bc047d5-a113-42a8-8151-d74808632c42" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_5bc047d5-a113-42a8-8151-d74808632c42" class="cnblogs_code_hide">
<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)"> 该示例演示了如何实现一个基础Agent(改编自<a href="</span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">https://github.com/langchain4j/langchain4j-examples</span><span style="color: rgba(0, 128, 0, 1)">">langchain4j官网示例</a>)
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 128, 0, 1)"> 注意:Agent只有与其他Agent结合使用时才更有用,后续步骤中将展示这一点。
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 128, 0, 1)"> 如果只有一个Agent,使用 AiService 会是更好的选择。
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 128, 0, 1)"> 这个基础Agent将用户的个人简介转换成一个简洁而完整的简历。
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 128, 0, 1)"> 注意:运行此程序可能需要一些时间,因为输出的简历会相当长,LLM也需要一些时间处理。
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> 菩提树下的杨过(yjmyzz.cnblogs.com)
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span><span style="color: rgba(128, 128, 128, 1)">@see</span><span style="color: rgba(0, 128, 0, 1)"> <a href="</span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">https://github.com/langchain4j/langchain4j-examples/blob/main/agentic-tutorial/src/main/java/_1_basic_agent/_1a_Basic_Agent_Example.java</span><span style="color: rgba(0, 128, 0, 1)">">_1a_Basic_Agent_Example</a>
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">@SpringBootApplication
</span><span style="color: rgba(0, 128, 128, 1)">11</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)"> _1a_Basic_Agent_Example {
</span><span style="color: rgba(0, 128, 128, 1)">12</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)">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)">14</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)">15</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)">16</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> CvGenerator cvGenerator =<span style="color: rgba(0, 0, 0, 1)"> AgenticServices
</span><span style="color: rgba(0, 128, 128, 1)">18</span> .agentBuilder(CvGenerator.<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)">19</span> <span style="color: rgba(0, 0, 0, 1)"> .chatModel(model)
</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)">定义输出对象的键</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> .outputKey("masterCv"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</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)"> 加载个人介绍</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> String lifeStory = StringLoader.loadFromResource("/documents/user_life_story.txt"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">26</span>
<span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 让 agent 生成简历</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> String cv =<span style="color: rgba(0, 0, 0, 1)"> cvGenerator.generateCv(lifeStory);
</span><span style="color: rgba(0, 128, 128, 1)">29</span>
<span style="color: rgba(0, 128, 128, 1)">30</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)">31</span> System.out.println("=== 简历 ==="<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">32</span> <span style="color: rgba(0, 0, 0, 1)"> System.out.println(cv);
</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(0, 128, 128, 1)">35</span>
<span style="color: rgba(0, 128, 128, 1)">36</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>时序图(简化版) - AI生成</p>
<p><img src="https://img2024.cnblogs.com/blog/27612/202601/27612-20260116193115675-1795457582.png" alt="01_basic_agent_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-20260116193147315-1309382226.png" alt="01_basic_agent_diagram_detail" width="480" loading="lazy" style="border: 1px solid rgba(0, 0, 0, 1)"></p>
<p>运行结果:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_8558f16e-7335-459a-b0b7-2f688ed9acaa" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_8558f16e-7335-459a-b0b7-2f688ed9acaa" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_8558f16e-7335-459a-b0b7-2f688ed9acaa" class="cnblogs_code_hide">
<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>-11T19:<span style="color: rgba(128, 0, 128, 1)">36</span>:<span style="color: rgba(128, 0, 128, 1)">17.012</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)">16080</span> --- [ main] 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)">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)"> 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注意事项:\n1. 不要编造任何事实\n2. 不要遗漏任何技能或经历\n3. 这份简历后续会进一步优化,请确保内容完整\n\n我的个人经历:John Doe 现居比利时安特卫普(Rue des Carmes 12, 2000 Antwerp),联系方式为 john.doe.dev@protonmail.com 或 +32 495 67 89 23。他在 LinkedIn 和 GitHub 上保持活跃。\r\n\r\n- 2020 年完成夜间 Java 集训营(2019–2020)后从机械工程领域转型至软件开发。\r\n- 拥有 4 年软件开发经验,其中最近 2 年专注于 Java 后端开发(Spring Boot、PostgreSQL、Kafka 基础)。\r\n- 开发了一款内部报价工具,将报价周转时间缩短约 35%。\r\n- 领导 3 人专项小组,将遗留 SOAP 服务迁移至 REST 架构。\r\n- 熟悉 Docker 与 CI 流水线(GitHub Actions)。\r\n- 具备 React 使用经验,曾开发内部管理面板(非核心优势)。\r\n- 重视代码整洁与可维护性,乐于指导实习生。\r\n- 偏好产品开发而非外包项目;不喜冗长会议,注重交付实际价值。\r\n- 语言:荷兰语(母语)、英语(C1)、法语(B1)。\r\n- 教育背景:机械工程学士(2016 年),Java 集训营(2019–2020)。\r\n- 个人项目包括一款小型预算管理应用(Spring + Vue)和一套家庭物联网系统(ESP32 + MQTT)。\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)">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)">12</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)">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)">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)">15</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)">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(0, 128, 128, 1)">18</span> <span style="color: rgba(128, 0, 128, 1)">2026</span>-<span style="color: rgba(128, 0, 128, 1)">01</span>-11T19:<span style="color: rgba(128, 0, 128, 1)">36</span>:<span style="color: rgba(128, 0, 128, 1)">24.079</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)">16080</span> --- [ main] d.l.http.client.log.LoggingHttpClient : HTTP response:
</span><span style="color: rgba(0, 128, 128, 1)">19</span> - status code: <span style="color: rgba(128, 0, 128, 1)">200</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> - headers: , [<span style="color: rgba(0, 0, 255, 1)">date</span>: Sun, <span style="color: rgba(128, 0, 128, 1)">11</span> Jan <span style="color: rgba(128, 0, 128, 1)">2026</span> <span style="color: rgba(128, 0, 128, 1)">11</span>:<span style="color: rgba(128, 0, 128, 1)">36</span>:<span style="color: rgba(128, 0, 128, 1)">24</span> GMT],
</span><span style="color: rgba(0, 128, 128, 1)">21</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-11T11:36:23.745953889Z</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)"># John Doe - 简历\n\n**地址**\nRue des Carmes 12, 2000 Antwerp, Belgium\n**邮箱**\njohn.doe.dev@protonmail.com\n**电话**\n+32 495 67 89 23\n**在线资料**\nLinkedIn | GitHub\n\n---\n\n## 职业摘要\n拥有4年软件开发经验的Java后端开发者,其中最近2年专注于Java生态系统(Spring Boot、PostgreSQL、Kafka)。具备从机械工程成功转型至软件开发的背景,擅长构建可维护的代码、优化流程,并乐于指导团队成员。注重产品价值交付,偏好产品导向的开发环境。\n\n---\n\n## 技能专长\n- **后端开发**: Java, Spring Boot, REST API, PostgreSQL, Kafka (基础)\n- **工具与流程**: Docker, CI/CD (GitHub Actions), Git\n- **前端经验**: React (内部工具开发), Vue.js (个人项目)\n- **软技能**: 代码整洁与可维护性、团队协作、指导实习生、问题解决\n- **语言**: 荷兰语 (母语), 英语 (C1), 法语 (B1)\n\n---\n\n## 职业经历\n**软件开发工程师**\n*2020年至今*\n- 开发内部报价工具,将报价周转时间缩短约35%。\n- 领导3人专项小组,完成遗留SOAP服务至REST架构的迁移。\n- 使用Spring Boot和PostgreSQL构建后端服务,并集成Kafka进行事件驱动通信。\n- 通过Docker容器化应用,利用GitHub Actions设置CI流水线以提高部署效率。\n- 曾开发React内部管理面板以支持业务运营(非核心职责)。\n- 积极指导实习生,提倡代码可读性与系统可维护性。\n\n---\n\n## 教育背景\n- **Java 夜间集训营**\n*2019–2020*\n集中学习Java编程、数据结构、Web开发与团队项目协作。\n\n- **机械工程学士**\n*2016年毕业*\n具备工程问题分析与系统化解决能力。\n\n---\n\n## 个人项目\n- **预算管理应用**\n使用Spring Boot与Vue.js构建的个人预算跟踪工具,支持支出分类与可视化报表。\n\n- **家庭物联网系统**\n基于ESP32微控制器与MQTT协议搭建的自动化家居监控系统,实现传感器数据采集与远程控制。\n\n---\n\n## 备注\n- 偏好产品导向的开发环境,注重交付实际价值而非冗长会议。\n- 对技术充满热情,持续通过个人项目与实践深化全栈技能。\n\n---\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)">6020764924</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)">387</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)">566</span><span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">22</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, 128, 1)">25</span> # John Doe -<span style="color: rgba(0, 0, 0, 1)"> 简历
</span><span style="color: rgba(0, 128, 128, 1)">26</span>
<span style="color: rgba(0, 128, 128, 1)">27</span> **地址**
<span style="color: rgba(0, 128, 128, 1)">28</span> Rue des Carmes <span style="color: rgba(128, 0, 128, 1)">12</span>, <span style="color: rgba(128, 0, 128, 1)">2000</span><span style="color: rgba(0, 0, 0, 1)"> Antwerp, Belgium
</span><span style="color: rgba(0, 128, 128, 1)">29</span> **邮箱**
<span style="color: rgba(0, 128, 128, 1)">30</span> <span style="color: rgba(0, 0, 0, 1)">john.doe.dev@protonmail.com
</span><span style="color: rgba(0, 128, 128, 1)">31</span> **电话**
<span style="color: rgba(0, 128, 128, 1)">32</span> +<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, 128, 128, 1)">33</span> **在线资料**
<span style="color: rgba(0, 128, 128, 1)">34</span> LinkedIn |<span style="color: rgba(0, 0, 0, 1)"> GitHub
</span><span style="color: rgba(0, 128, 128, 1)">35</span>
<span style="color: rgba(0, 128, 128, 1)">36</span> ---
<span style="color: rgba(0, 128, 128, 1)">37</span>
<span style="color: rgba(0, 128, 128, 1)">38</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)">拥有4年软件开发经验的Java后端开发者,其中最近2年专注于Java生态系统(Spring Boot、PostgreSQL、Kafka)。具备从机械工程成功转型至软件开发的背景,擅长构建可维护的代码、优化流程,并乐于指导团队成员。注重产品价值交付,偏好产品导向的开发环境。
</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(0, 128, 128, 1)">42</span>
<span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 0, 1)">## 技能专长
</span><span style="color: rgba(0, 128, 128, 1)">44</span> - **后端开发**<span style="color: rgba(0, 0, 0, 1)">: Java, Spring Boot, REST API, PostgreSQL, Kafka (基础)
</span><span style="color: rgba(0, 128, 128, 1)">45</span> - **工具与流程**: Docker, CI/<span style="color: rgba(0, 0, 0, 1)">CD (GitHub Actions), Git
</span><span style="color: rgba(0, 128, 128, 1)">46</span> - **前端经验**<span style="color: rgba(0, 0, 0, 1)">: React (内部工具开发), Vue.js (个人项目)
</span><span style="color: rgba(0, 128, 128, 1)">47</span> - **软技能**<span style="color: rgba(0, 0, 0, 1)">: 代码整洁与可维护性、团队协作、指导实习生、问题解决
</span><span style="color: rgba(0, 128, 128, 1)">48</span> - **语言**<span style="color: rgba(0, 0, 0, 1)">: 荷兰语 (母语), 英语 (C1), 法语 (B1)
</span><span style="color: rgba(0, 128, 128, 1)">49</span>
<span style="color: rgba(0, 128, 128, 1)">50</span> ---
<span style="color: rgba(0, 128, 128, 1)">51</span>
<span style="color: rgba(0, 128, 128, 1)">52</span> <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, 128, 1)">54</span> *2020年至今*
<span style="color: rgba(0, 128, 128, 1)">55</span> - 开发内部报价工具,将报价周转时间缩短约35%<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)"> 领导3人专项小组,完成遗留SOAP服务至REST架构的迁移。
</span><span style="color: rgba(0, 128, 128, 1)">57</span> -<span style="color: rgba(0, 0, 0, 1)"> 使用Spring Boot和PostgreSQL构建后端服务,并集成Kafka进行事件驱动通信。
</span><span style="color: rgba(0, 128, 128, 1)">58</span> -<span style="color: rgba(0, 0, 0, 1)"> 通过Docker容器化应用,利用GitHub Actions设置CI流水线以提高部署效率。
</span><span style="color: rgba(0, 128, 128, 1)">59</span> -<span style="color: rgba(0, 0, 0, 1)"> 曾开发React内部管理面板以支持业务运营(非核心职责)。
</span><span style="color: rgba(0, 128, 128, 1)">60</span> -<span style="color: rgba(0, 0, 0, 1)"> 积极指导实习生,提倡代码可读性与系统可维护性。
</span><span style="color: rgba(0, 128, 128, 1)">61</span>
<span style="color: rgba(0, 128, 128, 1)">62</span> ---
<span style="color: rgba(0, 128, 128, 1)">63</span>
<span style="color: rgba(0, 128, 128, 1)">64</span> <span style="color: rgba(0, 0, 0, 1)">## 教育背景
</span><span style="color: rgba(0, 128, 128, 1)">65</span> - **Java 夜间集训营**
<span style="color: rgba(0, 128, 128, 1)">66</span> *<span style="color: rgba(128, 0, 128, 1)">2019</span>–<span style="color: rgba(128, 0, 128, 1)">2020</span>*
<span style="color: rgba(0, 128, 128, 1)">67</span> <span style="color: rgba(0, 0, 0, 1)">集中学习Java编程、数据结构、Web开发与团队项目协作。
</span><span style="color: rgba(0, 128, 128, 1)">68</span>
<span style="color: rgba(0, 128, 128, 1)">69</span> - **机械工程学士**
<span style="color: rgba(0, 128, 128, 1)">70</span> *2016年毕业*
<span style="color: rgba(0, 128, 128, 1)">71</span> <span style="color: rgba(0, 0, 0, 1)">具备工程问题分析与系统化解决能力。
</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(0, 128, 128, 1)">74</span>
<span style="color: rgba(0, 128, 128, 1)">75</span> <span style="color: rgba(0, 0, 0, 1)">## 个人项目
</span><span style="color: rgba(0, 128, 128, 1)">76</span> - **预算管理应用**
<span style="color: rgba(0, 128, 128, 1)">77</span> <span style="color: rgba(0, 0, 0, 1)">使用Spring Boot与Vue.js构建的个人预算跟踪工具,支持支出分类与可视化报表。
</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, 0, 0, 1)">基于ESP32微控制器与MQTT协议搭建的自动化家居监控系统,实现传感器数据采集与远程控制。
</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, 128, 1)">83</span>
<span style="color: rgba(0, 128, 128, 1)">84</span> <span style="color: rgba(0, 0, 0, 1)">## 备注
</span><span style="color: rgba(0, 128, 128, 1)">85</span> -<span style="color: rgba(0, 0, 0, 1)"> 偏好产品导向的开发环境,注重交付实际价值而非冗长会议。
</span><span style="color: rgba(0, 128, 128, 1)">86</span> -<span style="color: rgba(0, 0, 0, 1)"> 对技术充满热情,持续通过个人项目与实践深化全栈技能。
</span><span style="color: rgba(0, 128, 128, 1)">87</span>
<span style="color: rgba(0, 128, 128, 1)">88</span> ---
<span style="color: rgba(0, 128, 128, 1)">89</span> *简历内容基于提供的经历信息整理,未添加任何编造内容,可随时进一步优化格式与重点。*</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p> 24-82行,就是基于“个人资料”生成的简历。</p>
<p> </p>
<p><span style="color: rgba(255, 0, 0, 1)">三、结构化输出</span></p>
<p>如果希望生成的简历,以结构化输出(即:直接输出POJO对象实例),可以稍微改进:</p>
<p><span style="color: rgba(255, 0, 0, 1)">3.1</span> 定义简历POJO类Cv</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_2be10ffc-6d8e-480a-8cdf-9cc4732eb532" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_2be10ffc-6d8e-480a-8cdf-9cc4732eb532" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_2be10ffc-6d8e-480a-8cdf-9cc4732eb532" class="cnblogs_code_hide">
<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)"> * 简历类
</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, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Cv {
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> @Description("候选人的专业技能,逗号串接"<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, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String skills;
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span> @Description("候选人的专业经历"<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, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String professionalExperience;
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> @Description("候选人的教育背景"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String studies;
</span><span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)"> @Override
</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, 0, 1)"> String toString() {
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">return</span> "CV:\n" +
<span style="color: rgba(0, 128, 128, 1)">17</span> "专业技能 = \"" + skills + "\"\n" +
<span style="color: rgba(0, 128, 128, 1)">18</span> "专业经历 = \"" + professionalExperience + "\"\n" +
<span style="color: rgba(0, 128, 128, 1)">19</span> "教育背景 = \"" + studies + "\"\n"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">21</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p><span style="color: rgba(255, 0, 0, 1)">3.2</span> 定义结构化Agent接口</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_d1c759da-db3f-4036-a9f5-0305c0943b30" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_d1c759da-db3f-4036-a9f5-0305c0943b30" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_d1c759da-db3f-4036-a9f5-0305c0943b30" class="cnblogs_code_hide">
<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)"> CvGeneratorStructuredOutput {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> @UserMessage(<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> <span style="color: rgba(0, 0, 0, 1)"> 请将其整理成一份清晰、完整的简历。
</span><span style="color: rgba(0, 128, 128, 1)"> 5</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> 1<span style="color: rgba(0, 0, 0, 1)">. 不要编造任何事实
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> 2<span style="color: rgba(0, 0, 0, 1)">. 不要遗漏任何技能或经历
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> 3<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)"> 我的个人经历:{{lifeStory}}
</span><span style="color: rgba(0, 128, 128, 1)">12</span> """)
<span style="color: rgba(0, 128, 128, 1)">13</span> @Agent("基于用户提供的信息生成规范的简历"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">14</span> Cv generateCv(@V("lifeStory"<span style="color: rgba(0, 0, 0, 1)">) String userInfo);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p><span style="color: rgba(255, 0, 0, 1)">3.3</span> 结构化输出Agent</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_e6a13cd8-46e1-4283-8e16-0e682ebd70b3" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_e6a13cd8-46e1-4283-8e16-0e682ebd70b3" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_e6a13cd8-46e1-4283-8e16-0e682ebd70b3" class="cnblogs_code_hide">
<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)">class</span><span style="color: rgba(0, 0, 0, 1)"> _1b_Basic_Agent_Example_Structured {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</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)"> 4</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)"> 5</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)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> CvGeneratorStructuredOutput cvGenerator =<span style="color: rgba(0, 0, 0, 1)"> AgenticServices
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> .agentBuilder(CvGeneratorStructuredOutput.<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)"> 9</span> <span style="color: rgba(0, 0, 0, 1)"> .chatModel(model)
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</span><span style="color: rgba(0, 128, 128, 1)">11</span>
<span style="color: rgba(0, 128, 128, 1)">12</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)">13</span> String lifeStory = StringLoader.loadFromResource("/documents/user_life_story.txt"<span style="color: rgba(0, 0, 0, 1)">);
</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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 让 agent 生成简历</span>
<span style="color: rgba(0, 128, 128, 1)">16</span> Cv cvStructured =<span style="color: rgba(0, 0, 0, 1)"> cvGenerator.generateCv(lifeStory);
</span><span style="color: rgba(0, 128, 128, 1)">17</span>
<span style="color: rgba(0, 128, 128, 1)">18</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)">19</span> System.out.println("=== 简历 ==="<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)"> System.out.println(cvStructured);
</span><span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">22</span> }</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>输出:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_69018fc2-4cc5-4dee-a280-f5ff64b5e5cc" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_69018fc2-4cc5-4dee-a280-f5ff64b5e5cc" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_69018fc2-4cc5-4dee-a280-f5ff64b5e5cc" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> 2026-01-11T19:58:32.855+08:00INFO 16512 --- [ main] 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> "model" : "deepseek-v3.1:671b-cloud"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> "messages"<span style="color: rgba(0, 0, 0, 1)"> : [ {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> "role" : "user"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> "content" : "以下是我的个人生活和职业经历信息,\n请将其整理成一份清晰、完整的简历。\n\n注意事项:\n1. 不要编造任何事实\n2. 不要遗漏任何技能或经历\n3. 这份简历后续会进一步优化,请确保内容完整\n\n我的个人经历:John Doe 现居比利时安特卫普(Rue des Carmes 12, 2000 Antwerp),联系方式为 john.doe.dev@protonmail.com 或 +32 495 67 89 23。他在 LinkedIn 和 GitHub 上保持活跃。\r\n\r\n- 2020 年完成夜间 Java 集训营(2019–2020)后从机械工程领域转型至软件开发。\r\n- 拥有 4 年软件开发经验,其中最近 2 年专注于 Java 后端开发(Spring Boot、PostgreSQL、Kafka 基础)。\r\n- 开发了一款内部报价工具,将报价周转时间缩短约 35%。\r\n- 领导 3 人专项小组,将遗留 SOAP 服务迁移至 REST 架构。\r\n- 熟悉 Docker 与 CI 流水线(GitHub Actions)。\r\n- 具备 React 使用经验,曾开发内部管理面板(非核心优势)。\r\n- 重视代码整洁与可维护性,乐于指导实习生。\r\n- 偏好产品开发而非外包项目;不喜冗长会议,注重交付实际价值。\r\n- 语言:荷兰语(母语)、英语(C1)、法语(B1)。\r\n- 教育背景:机械工程学士(2016 年),Java 集训营(2019–2020)。\r\n- 个人项目包括一款小型预算管理应用(Spring + Vue)和一套家庭物联网系统(ESP32 + MQTT)。\n\nYou must answer strictly in the following JSON format: {\n\"skills\": (候选人的专业技能,逗号串接; type: string),\n\"professionalExperience\": (候选人的专业经历; type: string),\n\"studies\": (候选人的教育背景; type: string)\n}"
<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> "options"<span style="color: rgba(0, 0, 0, 1)"> : {
</span><span style="color: rgba(0, 128, 128, 1)">12</span> "stop"<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)">},
</span><span style="color: rgba(0, 128, 128, 1)">14</span> "stream" : <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)">15</span> "tools"<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(0, 128, 128, 1)">18</span> 2026-01-11T19:58:36.010+08:00INFO 16512 --- [ main] d.l.http.client.log.LoggingHttpClient : HTTP response:
</span><span style="color: rgba(0, 128, 128, 1)">19</span> - status code: 200
<span style="color: rgba(0, 128, 128, 1)">20</span> - headers: , ,
</span><span style="color: rgba(0, 128, 128, 1)">21</span> - body: {"model":"deepseek-v3.1:671b-cloud","remote_model":"deepseek-v3.1:671b","remote_host":"https://ollama.com:443","created_at":"2026-01-11T11:58:35.375858113Z","message":{"role":"assistant","content":"{\n\"skills\": \"Java, Spring Boot, PostgreSQL, Kafka, REST API, Docker, CI/CD (GitHub Actions), React, 代码整洁与可维护性, 指导与协作, 荷兰语(母语), 英语(C1), 法语(B1)\",\n\"professionalExperience\": \"拥有4年软件开发经验,其中最近2年专注于Java后端开发。开发了一款内部报价工具,将报价周转时间缩短约35%。领导一个3人专项小组,成功将遗留SOAP服务迁移至REST架构。具备Docker与CI流水线(GitHub Actions)实践经验。有React使用经验,曾开发内部管理面板。重视代码质量,乐于指导实习生。偏好产品开发,注重交付实际价值。个人项目包括一款小型预算管理应用(Spring + Vue)和一套家庭物联网系统(ESP32 + MQTT)。\",\n\"studies\": \"机械工程学士(2016年毕业),Java集训营(2019-2020年)\"\n}"},"done":<span style="color: rgba(0, 0, 255, 1)">true</span>,"done_reason":"stop","total_duration":1828432886,"prompt_eval_count":444,"eval_count":212<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">22</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, 128, 1)">25</span> <span style="color: rgba(0, 0, 0, 1)">CV:
</span><span style="color: rgba(0, 128, 128, 1)">26</span> 专业技能 = "Java, Spring Boot, PostgreSQL, Kafka, REST API, Docker, CI/CD (GitHub Actions), React, 代码整洁与可维护性, 指导与协作, 荷兰语(母语), 英语(C1), 法语(B1)"
<span style="color: rgba(0, 128, 128, 1)">27</span> 专业经历 = "拥有4年软件开发经验,其中最近2年专注于Java后端开发。开发了一款内部报价工具,将报价周转时间缩短约35%。领导一个3人专项小组,成功将遗留SOAP服务迁移至REST架构。具备Docker与CI流水线(GitHub Actions)实践经验。有React使用经验,曾开发内部管理面板。重视代码质量,乐于指导实习生。偏好产品开发,注重交付实际价值。个人项目包括一款小型预算管理应用(Spring + Vue)和一套家庭物联网系统(ESP32 + MQTT)。"
<span style="color: rgba(0, 128, 128, 1)">28</span> 教育背景 = "机械工程学士(2016年毕业),Java集训营(2019-2020年)"</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>24-28行输出,即为Cv实例的toString结果。</p>
<p> </p>
<p><span style="color: rgba(255, 0, 0, 1)">小结:</span></p>
<p>本文示例了利用AgenticServices+@Agent注解生成1个最基本的Agent,虽然单就本例而言,还体现不出Agent与AiService的区别,但从下一篇开始,就能看到多个Agent之间的workflow编排。</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/19468327/agentic-patterns-using-langchain4j-1-basic-agent
頁:
[1]