書接上回,簡歷評估完後,根據評估結果,如果合格,公司就該通知面試,否則回郵件拒絕。也就是今天要演示的“條件工作流”。下面定義這2個分支對應的Agent:
一、定義不同分支的Agent
1.1 EmailAssistant (發郵件拒絕候選人Agent)
1 public interface EmailAssistant { 2 3 @Agent("向未通過篩選的候選人發送拒絕郵件,返回已發送郵件的ID,若無法發送則返回0") 4 @SystemMessage(""" 5 您需要向未通過第一輪評審的求職候選人發送一封友好的郵件。 6 同時,您需要將申請狀態更新為“已拒絕”。 7 您應返回已發送郵件的ID。 8 """) 9 @UserMessage(""" 10 被拒候選人:{{candidateContact}} 11 12 申請職位:{{jobDescription}} 13 """) 14 int send(@V("candidateContact") String candidateContact, @V("jobDescription") String jobDescription); 15 }
發送郵件時,需要候選人的聯繫信息,運行時我們用 candidate_contact.txt 做為輸入:
1 候選人聯繫卡片: 2 姓名:John Doe 3 地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普) 4 郵箱:john.doe.dev@protonmail.com 5 電話:+32 495 67 89 23
1.2 InterviewOrganizer (組織面試Agent)
1 public interface InterviewOrganizer { 2 3 @Agent("為申請人安排現場面試") 4 @SystemMessage(""" 5 您通過向所有相關員工發送日曆邀請來安排現場會議, 6 時間定在從當前日期起一週後的上午,時長為3小時。 7 這是相關的職位空缺:{{jobDescription}} 8 您還需通過祝賀郵件邀請候選人,告知面試詳情, 9 以及他/她來現場前需要注意的事項。 10 最後,您需要將申請狀態更新為“已邀請現場面試”。 11 """) 12 @UserMessage(""" 13 為此候選人安排現場面試會議(需遵守外部訪客政策):{{candidateContact}} 14 """) 15 String organize(@V("candidateContact") String candidateContact, @V("jobDescription") String jobDescription); 16 }
二、(可選)定義工具
不管是拒絕還是安排面試,處理過程中都有一些業務邏輯,比如:
拒絕流程:要先調用一些業務工具,發送拒絕郵件,更新簡歷申請狀態
安排面試流程:要先調用一些業務工具,獲取當前日期(LLM的知識截止於廠商的發佈日期,不識別今天)、獲取面試相關的公司員工列表(比如:面試官)、在公司議程表上發起面試日程、發送面試通知郵件、更新簡歷申請狀態
為此,我們需要定義這一系列工具(注:工具的實現,本例都用mock實現,僅為演示效果)
2.1 OrganizingTools
1 public class OrganizingTools { 2 3 @Tool 4 public Date getCurrentDate(){ 5 return new Date(); 6 } 7 8 @Tool("根據給定的職位描述ID,查找需要參加現場面試的人員的電子郵件地址和姓名") 9 public List<String> getInvolvedEmployeesForInterview(@P("職位描述ID") String jobDescriptionId){ 10 // 演示用虛擬實現 11 return new ArrayList<>(List.of( 12 "Anna Bolena: hiring.manager@company.com", 13 "Chris Durue: near.colleague@company.com", 14 "Esther Finnigan: vp@company.com")); 15 } 16 17 @Tool("根據電子郵件地址為員工創建日程條目") 18 public void createCalendarEntry(@P("員工電子郵件地址列表") List<String> emailAddress, @P("會議主題") String topic, @P("開始日期和時間,格式為yyyy-mm-dd hh:mm") String start, @P("結束日期和時間,格式為yyyy-mm-dd hh:mm") String end){ 19 // 演示用虛擬實現 20 System.out.println("*** 已創建日程條目 ***"); 21 System.out.println("主題:" + topic); 22 System.out.println("開始時間:" + start); 23 System.out.println("結束時間:" + end); 24 } 25 26 @Tool 27 public int sendEmail(@P("收件人電子郵件地址列表") List<String> to, @P("抄送電子郵件地址列表") List<String> cc, @P("郵件主題") String subject, @P("正文") String body){ 28 // 演示用虛擬實現 29 System.out.println("*** 已發送郵件 ***"); 30 System.out.println("收件人:" + to); 31 System.out.println("抄送:" + cc); 32 System.out.println("主題:" + subject); 33 System.out.println("正文:" + body); 34 return 1234; // 虛擬郵件ID 35 } 36 37 @Tool 38 public void updateApplicationStatus(@P("職位描述ID") String jobDescriptionId, @P("候選人(名,姓)") String candidateName, @P("新的申請狀態") String newStatus){ 39 // 演示用虛擬實現 40 System.out.println("*** 已更新申請狀態 ***"); 41 System.out.println("職位描述ID:" + jobDescriptionId); 42 System.out.println("候選人姓名:" + candidateName); 43 System.out.println("新狀態:" + newStatus); 44 } 45 }
2.2 RAG工具
通常每個公司都有一些自己的訪客制度,比如:車應該停在哪,衣冠必須端正,來面試時必須前台登記等等。這些LLM顯然不知道,需要藉助RAG工具
1 @Component("ragProvider") 2 public class RagProvider { 3 4 @Autowired 5 @Qualifier("ollamaEmbeddingModel") 6 OllamaEmbeddingModel ollamaEmbeddingModel; 7 8 public ContentRetriever loadHouseRulesRetriever() { 9 Document doc = loadDocument(toPath("documents/house_rules.txt")); 10 InMemoryEmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>(); 11 12 EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder() 13 .documentSplitter(DocumentSplitters.recursive(200, 10)) 14 .embeddingModel(ollamaEmbeddingModel) 15 .embeddingStore(store) 16 .build(); 17 18 ingestor.ingest(List.of(doc)); 19 20 return EmbeddingStoreContentRetriever.builder() 21 .embeddingStore(store) 22 .embeddingModel(ollamaEmbeddingModel) 23 .maxResults(2) 24 .minScore(0.8) 25 .build(); 26 } 27 28 public static Path toPath(String relativePath) { 29 try { 30 URL fileUrl = Utils.class.getClassLoader().getResource(relativePath); 31 return Paths.get(fileUrl.toURI()); 32 } catch (URISyntaxException e) { 33 throw new RuntimeException(e); 34 } 35 } 36 }
house_rules.txt內容如下:
1 1.僅允許在停車場後方指定户外區域吸煙。 2 2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。 3 3.員工須至少提前24小時通過內部日曆預訂會議室。 4 4.自行車必須停放在主樓外側的專用自行車停放區。 5 5.所有外部訪客須憑有效身份證件在前台登記方可進入。 6 6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。
三、條件工作流示例
1 /** 2 * 此示例演示了條件式智能體工作流。 3 * 基於評分和候選人資料,我們將執行以下操作之一: 4 * - 調用一個智能體,為該候選人的現場面試做好一切準備 5 * - 調用一個智能體,發送一封友好的郵件,告知我們不會推進該候選人的申請 6 * by 菩提樹下的楊過(yjmyzz.cnblogs.com) 7 */ 8 @SpringBootApplication 9 public class _5a_Conditional_Workflow_Example { 10 11 public static void main(String[] args) throws IOException { 12 ConfigurableApplicationContext context = SpringApplication.run(AgentDesignPatternApplication.class, args); 13 ChatModel model = context.getBean("ollamaChatModel", ChatModel.class); 14 RagProvider ragProvider = context.getBean("ragProvider", RagProvider.class); 15 16 // 2. 在此包中定義兩個子智能體: 17 // - EmailAssistant.java 18 // - InterviewOrganizer.java 19 20 // 3. 使用AgenticServices創建所有智能體 21 EmailAssistant emailAssistant = AgenticServices.agentBuilder(EmailAssistant.class) 22 .chatModel(model) 23 .tools(new OrganizingTools()) // 該智能體可以使用那裏定義的所有工具 24 .build(); 25 InterviewOrganizer interviewOrganizer = AgenticServices.agentBuilder(InterviewOrganizer.class) 26 .chatModel(model) 27 .tools(new OrganizingTools()) 28 .contentRetriever(ragProvider.loadHouseRulesRetriever()) // 這是如何為智能體添加RAG的方式 29 .build(); 30 31 // 4. 構建條件式工作流 32 UntypedAgent candidateResponder = AgenticServices // 使用UntypedAgent,除非您定義了合成的智能體,請參見_2_Sequential_Agent_Example 33 .conditionalBuilder() 34 .subAgents(agenticScope -> ((CvReview) agenticScope.readState("cvReview")).score >= 0.8, interviewOrganizer) 35 .subAgents(agenticScope -> ((CvReview) agenticScope.readState("cvReview")).score < 0.8, emailAssistant) 36 .build(); 37 // 重要提示:當定義了多個條件時,它們會按順序執行。 38 // 如果您想在這裏並行執行,請使用異步智能體,如_5b_Conditional_Workflow_Example_Async中所示 39 40 // 5. 從resources/documents/中的文本文件加載參數 41 String candidateCv = StringLoader.loadFromResource("/documents/tailored_cv.txt"); 42 String candidateContact = StringLoader.loadFromResource("/documents/candidate_contact.txt"); 43 String jobDescription = StringLoader.loadFromResource("/documents/job_description_backend.txt"); 44 CvReview cvReviewFail = new CvReview(0.6, "簡歷不錯,但缺少一些與後端職位相關的技術細節。"); 45 CvReview cvReviewPass = new CvReview(0.9, "簡歷非常出色,符合後端職位的所有要求。"); 46 47 // 5. 因為我們使用了無類型智能體,所以需要傳遞所有輸入參數的映射 48 Map<String, Object> arguments = Map.of( 49 "candidateCv", candidateCv, 50 "candidateContact", candidateContact, 51 "jobDescription", jobDescription, 52 "cvReview", cvReviewPass // 更改為cvReviewFail以查看另一個分支 53 ); 54 55 // 5. 調用條件式智能體,根據評審結果對候選人做出迴應 56 candidateResponder.invoke(arguments); 57 58 } 59 }
注:注意52行,這裏我們輸入的cvReview為0.9分的實例,即評估合格,可以安排面試。有興趣的朋友們,可以換成cvReviewFail實例,觀察下另1個分支的結果。
時序圖(簡化版)-AI生成
時序圖(詳細版)-AI生成
運行結果:
1 2026-01-17T16:53:37.524+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 2 - method: POST 3 - url: http://localhost:11434/api/embed 4 - headers: [Content-Type: application/json] 5 - body: { 6 "model" : "nomic-embed-text:latest", 7 "input" : [ "1.僅允許在停車場後方指定户外區域吸煙。\r\n2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。\r\n3.員工須至少提前24小時通過內部日曆預訂會議室。\r\n4.自行車必須停放在主樓外側的專用自行車停放區。\r\n5.所有外部訪客須憑有效身份證件在前台登記方可進入。\r\n6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。" ] 8 } 9 10 2026-01-17T16:53:42.826+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP response: 11 - status code: 200 12 - headers: [content-type: application/json; charset=utf-8], [date: Sat, 17 Jan 2026 08:53:42 GMT], [transfer-encoding: chunked] 13 - body: {"model":"nomic-embed-text:latest","embeddings":[[0.028599557,0.057497256,...-0.054139506]],"total_duration":5262584300,"load_duration":5247416900,"prompt_eval_count":161} 14 15 2026-01-17T16:53:42.871+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 16 - method: POST 17 - url: http://localhost:11434/api/embed 18 - headers: [Content-Type: application/json] 19 - body: { 20 "model" : "nomic-embed-text:latest", 21 "input" : [ "為此候選人安排現場面試會議(需遵守外部訪客政策):候選人聯繫卡片:\r\n姓名:John Doe\r\n地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普)\r\n郵箱:john.doe.dev@protonmail.com\r\n電話:+32 495 67 89 23\n" ] 22 } 23 24 2026-01-17T16:53:42.895+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP response: 25 - status code: 200 26 - headers: [content-type: application/json; charset=utf-8], [date: Sat, 17 Jan 2026 08:53:42 GMT], [transfer-encoding: chunked] 27 - body: {"model":"nomic-embed-text:latest","embeddings":[[0.018723998,0.067336,...-0.042845238]],"total_duration":22005300,"load_duration":12774100,"prompt_eval_count":88} 28 29 2026-01-17T16:53:42.939+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 30 - method: POST 31 - url: http://localhost:11434/api/chat 32 - headers: [Content-Type: application/json] 33 - body: { 34 "model" : "deepseek-v3.1:671b-cloud", 35 "messages" : [ { 36 "role" : "system", 37 "content" : "您通過向所有相關員工發送日曆邀請來安排現場會議,\n時間定在從當前日期起一週後的上午,時長為3小時。\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" 38 }, { 39 "role" : "user", 40 "content" : "為此候選人安排現場面試會議(需遵守外部訪客政策):候選人聯繫卡片:\r\n姓名:John Doe\r\n地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普)\r\n郵箱:john.doe.dev@protonmail.com\r\n電話:+32 495 67 89 23\n\n\nAnswer using the following information:\n1.僅允許在停車場後方指定户外區域吸煙。\r\n2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。\r\n3.員工須至少提前24小時通過內部日曆預訂會議室。\r\n4.自行車必須停放在主樓外側的專用自行車停放區。\r\n5.所有外部訪客須憑有效身份證件在前台登記方可進入。\r\n6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。" 41 } ], 42 "options" : { 43 "stop" : [ ] 44 }, 45 "stream" : false, 46 "tools" : [ { 47 "type" : "function", 48 "function" : { 49 "name" : "getInvolvedEmployeesForInterview", 50 "description" : "根據給定的職位描述ID,查找需要參加現場面試的人員的電子郵件地址和姓名", 51 "parameters" : { 52 ... 53 } 54 } 55 }, { 56 "type" : "function", 57 "function" : { 58 "name" : "createCalendarEntry", 59 "description" : "根據電子郵件地址為員工創建日程條目", 60 "parameters" : { 61 ... 62 } 63 } 64 }, { 65 "type" : "function", 66 "function" : { 67 "name" : "getCurrentDate" 68 } 69 }, { 70 "type" : "function", 71 "function" : { 72 "name" : "updateApplicationStatus", 73 "parameters" : { 74 ... 75 } 76 } 77 }, { 78 "type" : "function", 79 "function" : { 80 "name" : "sendEmail", 81 "parameters" : { 82 ... 83 } 84 } 85 } ] 86 } 87 88 2026-01-17T16:53:45.099+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP response: 89 - status code: 200 90 - headers: [content-type: application/json; charset=utf-8], [date: Sat, 17 Jan 2026 08:53:45 GMT], [transfer-encoding: chunked] 91 - body: {"model":"deepseek-v3.1:671b-cloud","remote_model":"deepseek-v3.1:671b","remote_host":"https://ollama.com:443","created_at":"2026-01-17T08:53:44.795645806Z","message":{"role":"assistant","content":"我將為您安排John Doe的現場面試。首先讓我獲取當前日期,然後找到需要參加面試的相關員工,並安排會議。","tool_calls":[{"id":"call_che9srkc","function":{"index":0,"name":"getCurrentDate","arguments":{}}}]},"done":true,"done_reason":"stop","total_duration":766029891,"prompt_eval_count":991,"eval_count":37} 92 93 94 2026-01-17T16:53:45.113+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 95 - method: POST 96 - url: http://localhost:11434/api/chat 97 - headers: [Content-Type: application/json] 98 - body: { 99 "model" : "deepseek-v3.1:671b-cloud", 100 "messages" : [ { 101 "role" : "system", 102 "content" : "您通過向所有相關員工發送日曆邀請來安排現場會議,\n時間定在從當前日期起一週後的上午,時長為3小時。\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" 103 }, { 104 "role" : "user", 105 "content" : "為此候選人安排現場面試會議(需遵守外部訪客政策):候選人聯繫卡片:\r\n姓名:John Doe\r\n地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普)\r\n郵箱:john.doe.dev@protonmail.com\r\n電話:+32 495 67 89 23\n\n\nAnswer using the following information:\n1.僅允許在停車場後方指定户外區域吸煙。\r\n2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。\r\n3.員工須至少提前24小時通過內部日曆預訂會議室。\r\n4.自行車必須停放在主樓外側的專用自行車停放區。\r\n5.所有外部訪客須憑有效身份證件在前台登記方可進入。\r\n6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。" 106 }, { 107 "role" : "assistant", 108 "content" : "我將為您安排John Doe的現場面試。首先讓我獲取當前日期,然後找到需要參加面試的相關員工,並安排會議。", 109 "tool_calls" : [ { 110 "function" : { 111 "name" : "getCurrentDate", 112 "arguments" : { } 113 } 114 } ] 115 }, { 116 "role" : "tool", 117 "content" : "1768640025109" 118 } ], 119 "options" : { 120 "stop" : [ ] 121 }, 122 "stream" : false, 123 "tools" : [ { 124 "type" : "function", 125 "function" : { 126 "name" : "getInvolvedEmployeesForInterview", 127 "description" : "根據給定的職位描述ID,查找需要參加現場面試的人員的電子郵件地址和姓名", 128 "parameters" : { 129 ... 130 } 131 } 132 }, { 133 "type" : "function", 134 "function" : { 135 "name" : "createCalendarEntry", 136 "description" : "根據電子郵件地址為員工創建日程條目", 137 "parameters" : { 138 ... 139 } 140 } 141 }, { 142 "type" : "function", 143 "function" : { 144 "name" : "getCurrentDate" 145 } 146 }, { 147 "type" : "function", 148 "function" : { 149 "name" : "updateApplicationStatus", 150 "parameters" : { 151 ... 152 } 153 } 154 }, { 155 "type" : "function", 156 "function" : { 157 "name" : "sendEmail", 158 "parameters" : { 159 ... 160 }, 161 "required" : [ "to", "cc", "subject", "body" ] 162 } 163 } 164 } ] 165 } 166 167 2026-01-17T16:53:46.607+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP response: 168 - status code: 200 169 - headers: [content-type: application/json; charset=utf-8], [date: Sat, 17 Jan 2026 08:53:46 GMT], [transfer-encoding: chunked] 170 - body: {"model":"deepseek-v3.1:671b-cloud","remote_model":"deepseek-v3.1:671b","remote_host":"https://ollama.com:443","created_at":"2026-01-17T08:53:45.888540222Z","message":{"role":"assistant","content":"","tool_calls":[{"id":"call_pb0rggf6","function":{"index":0,"name":"getInvolvedEmployeesForInterview","arguments":{"jobDescriptionId":"123A"}}}]},"done":true,"done_reason":"stop","total_duration":645456006,"prompt_eval_count":1035,"eval_count":21} 171 172 173 2026-01-17T16:53:46.609+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 174 - method: POST 175 - url: http://localhost:11434/api/chat 176 - headers: [Content-Type: application/json] 177 - body: { 178 "model" : "deepseek-v3.1:671b-cloud", 179 "messages" : [ { 180 "role" : "system", 181 "content" : "您通過向所有相關員工發送日曆邀請來安排現場會議,\n時間定在從當前日期起一週後的上午,時長為3小時。\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" 182 }, { 183 "role" : "user", 184 "content" : "為此候選人安排現場面試會議(需遵守外部訪客政策):候選人聯繫卡片:\r\n姓名:John Doe\r\n地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普)\r\n郵箱:john.doe.dev@protonmail.com\r\n電話:+32 495 67 89 23\n\n\nAnswer using the following information:\n1.僅允許在停車場後方指定户外區域吸煙。\r\n2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。\r\n3.員工須至少提前24小時通過內部日曆預訂會議室。\r\n4.自行車必須停放在主樓外側的專用自行車停放區。\r\n5.所有外部訪客須憑有效身份證件在前台登記方可進入。\r\n6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。" 185 }, { 186 "role" : "assistant", 187 "content" : "我將為您安排John Doe的現場面試。首先讓我獲取當前日期,然後找到需要參加面試的相關員工,並安排會議。", 188 "tool_calls" : [ { 189 "function" : { 190 "name" : "getCurrentDate", 191 "arguments" : { } 192 } 193 } ] 194 }, { 195 "role" : "tool", 196 "content" : "1768640025109" 197 }, { 198 "role" : "assistant", 199 "tool_calls" : [ { 200 "function" : { 201 "name" : "getInvolvedEmployeesForInterview", 202 "arguments" : { 203 "jobDescriptionId" : "123A" 204 } 205 } 206 } ] 207 }, { 208 "role" : "tool", 209 "content" : "[ \"Anna Bolena: hiring.manager@company.com\", \"Chris Durue: near.colleague@company.com\", \"Esther Finnigan: vp@company.com\" ]" 210 } ], 211 "options" : { 212 "stop" : [ ] 213 }, 214 "stream" : false, 215 "tools" : [ { 216 "type" : "function", 217 "function" : { 218 "name" : "getInvolvedEmployeesForInterview", 219 "description" : "根據給定的職位描述ID,查找需要參加現場面試的人員的電子郵件地址和姓名", 220 "parameters" : { 221 ... 222 } 223 } 224 }, { 225 "type" : "function", 226 "function" : { 227 "name" : "createCalendarEntry", 228 "description" : "根據電子郵件地址為員工創建日程條目", 229 "parameters" : { 230 ... 231 } 232 } 233 }, { 234 "type" : "function", 235 "function" : { 236 "name" : "getCurrentDate" 237 } 238 }, { 239 "type" : "function", 240 "function" : { 241 "name" : "updateApplicationStatus", 242 "parameters" : { 243 ... 244 } 245 } 246 }, { 247 "type" : "function", 248 "function" : { 249 "name" : "sendEmail", 250 "parameters" : { 251 ... 252 } 253 } 254 } ] 255 } 256 257 2026-01-17T16:53:50.266+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP response: 258 - status code: 200 259 - headers: [content-type: application/json; charset=utf-8], [date: Sat, 17 Jan 2026 08:53:50 GMT], [transfer-encoding: chunked] 260 - body: {"model":"deepseek-v3.1:671b-cloud","remote_model":"deepseek-v3.1:671b","remote_host":"https://ollama.com:443","created_at":"2026-01-17T08:53:48.769553461Z","message":{"role":"assistant","content":"現在我已經獲取了需要參加面試的員工信息。讓我創建面試會議日程:","tool_calls":[{"id":"call_qzbeevl7","function":{"index":0,"name":"createCalendarEntry","arguments":{"emailAddress":["hiring.manager@company.com","near.colleague@company.com","vp@company.com"],"end":"2025-11–21 12:00","start":"2025-11–21 09:00","topic":"後端工程師職位現場面試 - John Doe"}}}]},"done":true,"done_reason":"stop","total_duration":2032866290,"prompt_eval_count":1095,"eval_count":88} 261 262 263 *** 已創建日程條目 *** 264 主題:後端工程師職位現場面試 - John Doe 265 開始時間:2025-11–21 09:00 266 結束時間:2025-11–21 12:00 267 2026-01-17T16:53:50.272+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 268 - method: POST 269 - url: http://localhost:11434/api/chat 270 - headers: [Content-Type: application/json] 271 - body: { 272 "model" : "deepseek-v3.1:671b-cloud", 273 "messages" : [ { 274 "role" : "system", 275 "content" : "您通過向所有相關員工發送日曆邀請來安排現場會議,\n時間定在從當前日期起一週後的上午,時長為3小時。\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" 276 }, { 277 "role" : "user", 278 "content" : "為此候選人安排現場面試會議(需遵守外部訪客政策):候選人聯繫卡片:\r\n姓名:John Doe\r\n地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普)\r\n郵箱:john.doe.dev@protonmail.com\r\n電話:+32 495 67 89 23\n\n\nAnswer using the following information:\n1.僅允許在停車場後方指定户外區域吸煙。\r\n2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。\r\n3.員工須至少提前24小時通過內部日曆預訂會議室。\r\n4.自行車必須停放在主樓外側的專用自行車停放區。\r\n5.所有外部訪客須憑有效身份證件在前台登記方可進入。\r\n6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。" 279 }, { 280 "role" : "assistant", 281 "content" : "我將為您安排John Doe的現場面試。首先讓我獲取當前日期,然後找到需要參加面試的相關員工,並安排會議。", 282 "tool_calls" : [ { 283 "function" : { 284 "name" : "getCurrentDate", 285 "arguments" : { } 286 } 287 } ] 288 }, { 289 "role" : "tool", 290 "content" : "1768640025109" 291 }, { 292 "role" : "assistant", 293 "tool_calls" : [ { 294 "function" : { 295 "name" : "getInvolvedEmployeesForInterview", 296 "arguments" : { 297 "jobDescriptionId" : "123A" 298 } 299 } 300 } ] 301 }, { 302 "role" : "tool", 303 "content" : "[ \"Anna Bolena: hiring.manager@company.com\", \"Chris Durue: near.colleague@company.com\", \"Esther Finnigan: vp@company.com\" ]" 304 }, { 305 "role" : "assistant", 306 "content" : "現在我已經獲取了需要參加面試的員工信息。讓我創建面試會議日程:", 307 "tool_calls" : [ { 308 "function" : { 309 "name" : "createCalendarEntry", 310 "arguments" : { 311 "emailAddress" : [ "hiring.manager@company.com", "near.colleague@company.com", "vp@company.com" ], 312 "start" : "2025-11–21 09:00", 313 "topic" : "後端工程師職位現場面試 - John Doe", 314 "end" : "2025-11–21 12:00" 315 } 316 } 317 } ] 318 }, { 319 "role" : "tool", 320 "content" : "Success" 321 } ], 322 "options" : { 323 "stop" : [ ] 324 }, 325 "stream" : false, 326 "tools" : [ { 327 "type" : "function", 328 "function" : { 329 "name" : "getInvolvedEmployeesForInterview", 330 "description" : "根據給定的職位描述ID,查找需要參加現場面試的人員的電子郵件地址和姓名", 331 "parameters" : { 332 ... 333 } 334 } 335 }, { 336 "type" : "function", 337 "function" : { 338 "name" : "createCalendarEntry", 339 "description" : "根據電子郵件地址為員工創建日程條目", 340 "parameters" : { 341 ... 342 } 343 } 344 }, { 345 "type" : "function", 346 "function" : { 347 "name" : "getCurrentDate" 348 } 349 }, { 350 "type" : "function", 351 "function" : { 352 "name" : "updateApplicationStatus", 353 "parameters" : { 354 ... 355 } 356 } 357 }, { 358 "type" : "function", 359 "function" : { 360 "name" : "sendEmail", 361 "parameters" : { 362 ... 363 } 364 } 365 } ] 366 } 367 368 2026-01-17T16:54:10.480+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP response: 369 - status code: 200 370 - headers: [content-type: application/json; charset=utf-8], [date: Sat, 17 Jan 2026 08:54:10 GMT], [transfer-encoding: chunked] 371 - body: {"model":"deepseek-v3.1:671b-cloud","remote_model":"deepseek-v3.1:671b","remote_host":"https://ollama.com:443","created_at":"2026-01-17T08:54:09.753507501Z","message":{"role":"assistant","content":"現在我將發送祝賀郵件給候選人John Doe,並告知面試詳情:","tool_calls":[{"id":"call_eudsd6uf","function":{"index":0,"name":"sendEmail","arguments":{"body":"尊敬的John Doe先生/女士:\n\n恭喜您!您已成功通過我們後端工程師職位的初步篩選。我們誠摯邀請您參加現場面試。\n\n面試詳情:\n- 日期:從當前日期起一週後(2025年11月21日)\n- 時間:上午9:00 - 12:00(時長3小時)\n- 地點:Rue des Carmes 12, 2000 Antwerp, Belgium\n\n現場面試注意事項:\n\n重要訪客政策提醒:\n1. 所有外部訪客須憑有效身份證件在前台登記方可進入\n2. 您將被授予臨時訪客證,請確保佩戴在顯眼位置\n3. 僅允許在停車場後方指定户外區域吸煙\n4. 辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談\n5. 如有自行車,請停放在主樓外側的專用自行車停放區\n\n我們期待與您見面,討論您在金融科技後端開發方面的經驗與潛力。\n\n祝好,\n招聘團隊","cc":["hiring.manager@company.com"],"subject":"祝賀!後端工程師職位現場面試邀請","to":["john.doe.dev@protonmail.com"]}}}]},"done":true,"done_reason":"stop","total_duration":19351550481,"prompt_eval_count":1186,"eval_count":301} 372 373 374 *** 已發送郵件 *** 375 收件人:[john.doe.dev@protonmail.com] 376 抄送:[hiring.manager@company.com] 377 主題:祝賀!後端工程師職位現場面試邀請 378 正文:尊敬的John Doe先生/女士: 379 380 恭喜您!您已成功通過我們後端工程師職位的初步篩選。我們誠摯邀請您參加現場面試。 381 382 面試詳情: 383 - 日期:從當前日期起一週後(2025年11月21日) 384 - 時間:上午9:00 - 12:00(時長3小時) 385 - 地點:Rue des Carmes 12, 2000 Antwerp, Belgium 386 387 現場面試注意事項: 388 389 重要訪客政策提醒: 390 1. 所有外部訪客須憑有效身份證件在前台登記方可進入 391 2. 您將被授予臨時訪客證,請確保佩戴在顯眼位置 392 3. 僅允許在停車場後方指定户外區域吸煙 393 4. 辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談 394 5. 如有自行車,請停放在主樓外側的專用自行車停放區 395 396 我們期待與您見面,討論您在金融科技後端開發方面的經驗與潛力。 397 398 祝好, 399 招聘團隊 400 2026-01-17T16:54:10.484+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 401 - method: POST 402 - url: http://localhost:11434/api/chat 403 - headers: [Content-Type: application/json] 404 - body: { 405 "model" : "deepseek-v3.1:671b-cloud", 406 "messages" : [ { 407 "role" : "system", 408 "content" : "您通過向所有相關員工發送日曆邀請來安排現場會議,\n時間定在從當前日期起一週後的上午,時長為3小時。\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" 409 }, { 410 "role" : "user", 411 "content" : "為此候選人安排現場面試會議(需遵守外部訪客政策):候選人聯繫卡片:\r\n姓名:John Doe\r\n地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普)\r\n郵箱:john.doe.dev@protonmail.com\r\n電話:+32 495 67 89 23\n\n\nAnswer using the following information:\n1.僅允許在停車場後方指定户外區域吸煙。\r\n2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。\r\n3.員工須至少提前24小時通過內部日曆預訂會議室。\r\n4.自行車必須停放在主樓外側的專用自行車停放區。\r\n5.所有外部訪客須憑有效身份證件在前台登記方可進入。\r\n6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。" 412 }, { 413 "role" : "assistant", 414 "content" : "我將為您安排John Doe的現場面試。首先讓我獲取當前日期,然後找到需要參加面試的相關員工,並安排會議。", 415 "tool_calls" : [ { 416 "function" : { 417 "name" : "getCurrentDate", 418 "arguments" : { } 419 } 420 } ] 421 }, { 422 "role" : "tool", 423 "content" : "1768640025109" 424 }, { 425 "role" : "assistant", 426 "tool_calls" : [ { 427 "function" : { 428 "name" : "getInvolvedEmployeesForInterview", 429 "arguments" : { 430 "jobDescriptionId" : "123A" 431 } 432 } 433 } ] 434 }, { 435 "role" : "tool", 436 "content" : "[ \"Anna Bolena: hiring.manager@company.com\", \"Chris Durue: near.colleague@company.com\", \"Esther Finnigan: vp@company.com\" ]" 437 }, { 438 "role" : "assistant", 439 "content" : "現在我已經獲取了需要參加面試的員工信息。讓我創建面試會議日程:", 440 "tool_calls" : [ { 441 "function" : { 442 "name" : "createCalendarEntry", 443 "arguments" : { 444 "emailAddress" : [ "hiring.manager@company.com", "near.colleague@company.com", "vp@company.com" ], 445 "start" : "2025-11–21 09:00", 446 "topic" : "後端工程師職位現場面試 - John Doe", 447 "end" : "2025-11–21 12:00" 448 } 449 } 450 } ] 451 }, { 452 "role" : "tool", 453 "content" : "Success" 454 }, { 455 "role" : "assistant", 456 "content" : "現在我將發送祝賀郵件給候選人John Doe,並告知面試詳情:", 457 "tool_calls" : [ { 458 "function" : { 459 "name" : "sendEmail", 460 "arguments" : { 461 "cc" : [ "hiring.manager@company.com" ], 462 "subject" : "祝賀!後端工程師職位現場面試邀請", 463 "to" : [ "john.doe.dev@protonmail.com" ], 464 "body" : "尊敬的John Doe先生/女士:\n\n恭喜您!您已成功通過我們後端工程師職位的初步篩選。我們誠摯邀請您參加現場面試。\n\n面試詳情:\n- 日期:從當前日期起一週後(2025年11月21日)\n- 時間:上午9:00 - 12:00(時長3小時)\n- 地點:Rue des Carmes 12, 2000 Antwerp, Belgium\n\n現場面試注意事項:\n\n重要訪客政策提醒:\n1. 所有外部訪客須憑有效身份證件在前台登記方可進入\n2. 您將被授予臨時訪客證,請確保佩戴在顯眼位置\n3. 僅允許在停車場後方指定户外區域吸煙\n4. 辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談\n5. 如有自行車,請停放在主樓外側的專用自行車停放區\n\n我們期待與您見面,討論您在金融科技後端開發方面的經驗與潛力。\n\n祝好,\n招聘團隊" 465 } 466 } 467 } ] 468 }, { 469 "role" : "tool", 470 "content" : "1234" 471 } ], 472 "options" : { 473 "stop" : [ ] 474 }, 475 "stream" : false, 476 "tools" : [ { 477 "type" : "function", 478 "function" : { 479 "name" : "getInvolvedEmployeesForInterview", 480 "description" : "根據給定的職位描述ID,查找需要參加現場面試的人員的電子郵件地址和姓名", 481 "parameters" : { 482 ... 483 } 484 } 485 }, { 486 "type" : "function", 487 "function" : { 488 "name" : "createCalendarEntry", 489 "description" : "根據電子郵件地址為員工創建日程條目", 490 "parameters" : { 491 ... 492 } 493 } 494 }, { 495 "type" : "function", 496 "function" : { 497 "name" : "getCurrentDate" 498 } 499 }, { 500 "type" : "function", 501 "function" : { 502 "name" : "updateApplicationStatus", 503 "parameters" : { 504 ... 505 } 506 } 507 }, { 508 "type" : "function", 509 "function" : { 510 "name" : "sendEmail", 511 "parameters" : { 512 ... 513 } 514 } 515 } ] 516 } 517 518 2026-01-17T16:54:12.455+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP response: 519 - status code: 200 520 - headers: [content-type: application/json; charset=utf-8], [date: Sat, 17 Jan 2026 08:54:12 GMT], [transfer-encoding: chunked] 521 - body: {"model":"deepseek-v3.1:671b-cloud","remote_model":"deepseek-v3.1:671b","remote_host":"https://ollama.com:443","created_at":"2026-01-17T08:54:11.733376347Z","message":{"role":"assistant","content":"最後,我將更新申請狀態:","tool_calls":[{"id":"call_rmbx9gyb","function":{"index":0,"name":"updateApplicationStatus","arguments":{"candidateName":"John Doe","jobDescriptionId":"123A","newStatus":"已邀請現場面試"}}}]},"done":true,"done_reason":"stop","total_duration":1119737172,"prompt_eval_count":1491,"eval_count":39} 522 523 524 *** 已更新申請狀態 *** 525 職位描述ID:123A 526 候選人姓名:John Doe 527 新狀態:已邀請現場面試 528 2026-01-17T16:54:12.458+08:00 INFO 15192 --- [langchain4j-study] [ main] d.l.http.client.log.LoggingHttpClient : HTTP request: 529 - method: POST 530 - url: http://localhost:11434/api/chat 531 - headers: [Content-Type: application/json] 532 - body: { 533 "model" : "deepseek-v3.1:671b-cloud", 534 "messages" : [ { 535 "role" : "system", 536 "content" : "您通過向所有相關員工發送日曆邀請來安排現場會議,\n時間定在從當前日期起一週後的上午,時長為3小時。\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" 537 }, { 538 "role" : "user", 539 "content" : "為此候選人安排現場面試會議(需遵守外部訪客政策):候選人聯繫卡片:\r\n姓名:John Doe\r\n地址:Rue des Carmes 12, 2000 Antwerp, Belgium(比利時安特衞普)\r\n郵箱:john.doe.dev@protonmail.com\r\n電話:+32 495 67 89 23\n\n\nAnswer using the following information:\n1.僅允許在停車場後方指定户外區域吸煙。\r\n2.辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談。\r\n3.員工須至少提前24小時通過內部日曆預訂會議室。\r\n4.自行車必須停放在主樓外側的專用自行車停放區。\r\n5.所有外部訪客須憑有效身份證件在前台登記方可進入。\r\n6.外部訪客均須佩戴臨時訪客證,並確保證件清晰可見。" 540 }, { 541 "role" : "assistant", 542 "content" : "我將為您安排John Doe的現場面試。首先讓我獲取當前日期,然後找到需要參加面試的相關員工,並安排會議。", 543 "tool_calls" : [ { 544 "function" : { 545 "name" : "getCurrentDate", 546 "arguments" : { } 547 } 548 } ] 549 }, { 550 "role" : "tool", 551 "content" : "1768640025109" 552 }, { 553 "role" : "assistant", 554 "tool_calls" : [ { 555 "function" : { 556 "name" : "getInvolvedEmployeesForInterview", 557 "arguments" : { 558 "jobDescriptionId" : "123A" 559 } 560 } 561 } ] 562 }, { 563 "role" : "tool", 564 "content" : "[ \"Anna Bolena: hiring.manager@company.com\", \"Chris Durue: near.colleague@company.com\", \"Esther Finnigan: vp@company.com\" ]" 565 }, { 566 "role" : "assistant", 567 "content" : "現在我已經獲取了需要參加面試的員工信息。讓我創建面試會議日程:", 568 "tool_calls" : [ { 569 "function" : { 570 "name" : "createCalendarEntry", 571 "arguments" : { 572 "emailAddress" : [ "hiring.manager@company.com", "near.colleague@company.com", "vp@company.com" ], 573 "start" : "2025-11–21 09:00", 574 "topic" : "後端工程師職位現場面試 - John Doe", 575 "end" : "2025-11–21 12:00" 576 } 577 } 578 } ] 579 }, { 580 "role" : "tool", 581 "content" : "Success" 582 }, { 583 "role" : "assistant", 584 "content" : "現在我將發送祝賀郵件給候選人John Doe,並告知面試詳情:", 585 "tool_calls" : [ { 586 "function" : { 587 "name" : "sendEmail", 588 "arguments" : { 589 "cc" : [ "hiring.manager@company.com" ], 590 "subject" : "祝賀!後端工程師職位現場面試邀請", 591 "to" : [ "john.doe.dev@protonmail.com" ], 592 "body" : "尊敬的John Doe先生/女士:\n\n恭喜您!您已成功通過我們後端工程師職位的初步篩選。我們誠摯邀請您參加現場面試。\n\n面試詳情:\n- 日期:從當前日期起一週後(2025年11月21日)\n- 時間:上午9:00 - 12:00(時長3小時)\n- 地點:Rue des Carmes 12, 2000 Antwerp, Belgium\n\n現場面試注意事項:\n\n重要訪客政策提醒:\n1. 所有外部訪客須憑有效身份證件在前台登記方可進入\n2. 您將被授予臨時訪客證,請確保佩戴在顯眼位置\n3. 僅允許在停車場後方指定户外區域吸煙\n4. 辦公區安靜時段為下午2點至4點,請避免在開放空間大聲交談\n5. 如有自行車,請停放在主樓外側的專用自行車停放區\n\n我們期待與您見面,討論您在金融科技後端開發方面的經驗與潛力。\n\n祝好,\n招聘團隊" 593 } 594 } 595 } ] 596 }, { 597 "role" : "tool", 598 "content" : "1234" 599 }, { 600 "role" : "assistant", 601 "content" : "最後,我將更新申請狀態:", 602 "tool_calls" : [ { 603 "function" : { 604 "name" : "updateApplicationStatus", 605 "arguments" : { 606 "candidateName" : "John Doe", 607 "newStatus" : "已邀請現場面試", 608 "jobDescriptionId" : "123A" 609 } 610 } 611 } ] 612 }, { 613 "role" : "tool", 614 "content" : "Success" 615 } ], 616 "options" : { 617 "stop" : [ ] 618 }, 619 "stream" : false, 620 "tools" : [ { 621 "type" : "function", 622 "function" : { 623 "name" : "getInvolvedEmployeesForInterview", 624 "description" : "根據給定的職位描述ID,查找需要參加現場面試的人員的電子郵件地址和姓名", 625 "parameters" : { 626 ... 627 } 628 } 629 }, { 630 "type" : "function", 631 "function" : { 632 "name" : "createCalendarEntry", 633 "description" : "根據電子郵件地址為員工創建日程條目", 634 "parameters" : { 635 ... 636 } 637 } 638 }, { 639 "type" : "function", 640 "function" : { 641 "name" : "getCurrentDate" 642 } 643 }, { 644 "type" : "function", 645 "function" : { 646 "name" : "updateApplicationStatus", 647 "parameters" : { 648 ... 649 } 650 } 651 }, { 652 "type" : "function", 653 "function" : { 654 "name" : "sendEmail", 655 "parameters" : { 656 ... 657 } 658 } 659 } ] 660 }
輸出內容比較長,解釋一下:
- 3-8行,是RAG初始化時,將house_rules.txt(訪客制度)向量化
- 16-21行,這次RAG的向量化,可能有朋友會產生疑惑,根源在於:
這裏將InterviewOrganizer實例附加了RAG工具後,RAG會將對應Agent中的用户Prompt自動向量化,即:
- 30-86是首次與LLM交互,注意tools節點,這裏把所有可用的工具(包括工具的入參及要求)也一併給了LLM,以便讓LLM決定需要調用哪些工具。
- 91行,LLM的首次回答中,指出需要調用工具:getCurrentDate , 後面就不一一解釋,大家按順序看下去,應該不難理解
- 263行,表示已創建了面試的日程
- 374行,表示已給相關干係人發送了面試郵件通知
- 524行,表示更新了簡歷的申請狀態
文中示例代碼:
https://github.com/yjmyzz/agentic_turoial_with_langchain4j
參考:
Building Effective AI Agents \ Anthropic
[譯] AI Workflow & AI Agent:架構、模式與工程建議(Anthropic,2024)
Agents and Agentic AI | LangChain4j