博客 / 詳情

返回

Agent設計模式學習(基於langchain4j實現)(5) - 條件工作流

書接上回,簡歷評估完後,根據評估結果,如果合格,公司就該通知面試,否則回郵件拒絕。也就是今天要演示的“條件工作流”。下面定義這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生成

05_condional_diagram_simple

時序圖(詳細版)-AI生成

05_condional_diagram_detail

 運行結果:

  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-1121 09:00
266 結束時間:2025-1121 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(訪客制度)向量化

image

  • 16-21行,這次RAG的向量化,可能有朋友會產生疑惑,根源在於:

image

這裏將InterviewOrganizer實例附加了RAG工具後,RAG會將對應Agent中的用户Prompt自動向量化,即:

image

  • 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

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.