{"id":10021437,"date":"2026-08-27T12:01:07","date_gmt":"2026-08-27T04:01:07","guid":{"rendered":"https:\/\/itmax.cn\/?p=10021437"},"modified":"2026-08-27T12:01:07","modified_gmt":"2026-08-27T04:01:07","slug":"%e4%bc%81%e4%b8%9a%e7%ba%a7-multiagent-%e7%9a%84%e8%ae%b0%e5%bf%86%e7%b3%bb%e7%bb%9f%ef%bc%9a%e7%9f%ad%e6%9c%9f%e4%b8%8a%e4%b8%8b%e6%96%87%e4%b8%8e%e5%9b%9b%e5%b1%82%e8%ae%b0%e5%bf%86%e6%9e%b6","status":"publish","type":"post","link":"https:\/\/itmax.cn\/?p=10021437","title":{"rendered":"\u4f01\u4e1a\u7ea7 MultiAgent \u7684\u8bb0\u5fc6\u7cfb\u7edf\uff1a\u77ed\u671f\u4e0a\u4e0b\u6587\u4e0e\u56db\u5c42\u8bb0\u5fc6\u67b6\u6784\u5b9e\u73b0\uff5c\u5f97\u7269\u6280\u672f"},"content":{"rendered":"<h2>\u4e00\u3001\u80cc\u666f\u53ca\u6574\u4f53\u67b6\u6784\u6982\u89c8<\/h2>\n<p>\u5728 MultiAgent \u5e73\u53f0\u4e2d\uff0cAgent \u4e00\u6b21\u8bf7\u6c42\u53ef\u80fd\u540c\u65f6\u7ecf\u8fc7\u6a21\u578b\u3001MCP\/A2A \u5de5\u5177\u3001RAG\u3001Workflow \u548c Sandbox\uff0c\u8fd8\u8981\u5728\u591a\u8f6e\u5bf9\u8bdd\u548c\u8de8\u4f1a\u8bdd\u534f\u4f5c\u4e2d\u8bb0\u4f4f\u7528\u6237\u504f\u597d\u3001\u4efb\u52a1\u8fdb\u5c55\u4e0e\u534f\u4f5c\u7ea6\u5b9a\u3002\u56e0\u6b64\u8bb0\u5fc6\u6a21\u5757\u4e0d\u662f\u72ec\u7acb\u5916\u6302\uff0c\u800c\u662f Agent \u6267\u884c\u94fe\u8def\u7684\u4e00\u90e8\u5206\u3002<\/p>\n<p>\u5728\u672c\u9879\u76ee\u4e2d\uff0c\u8bb0\u5fc6\u4e0d\u662f\u628a\u5168\u90e8\u5386\u53f2\u7b80\u5355\u62fc\u5230 Prompt\uff0c\u800c\u662f\u5206\u522b\u627f\u63a5\u4f1a\u8bdd\u4e0a\u4e0b\u6587\u3001\u8de8\u4f1a\u8bdd\u4fe1\u606f\u548c\u4e0a\u4e0b\u6587\u5173\u8054\uff1a<\/p>\n<ul>\n<li><strong>\u4f1a\u8bdd\u5ef6\u7eed\uff1a<\/strong> \u77ed\u671f\u5386\u53f2\u65e0\u6cd5\u652f\u6301\u6307\u4ee3\u6d88\u89e3\u548c\u4efb\u52a1\u5ef6\u7eed\u3002<\/li>\n<li><strong>\u8de8\u4f1a\u8bdd\u590d\u7528\uff1a<\/strong> \u8de8\u4f1a\u8bdd\u65e0\u6cd5\u590d\u7528\u7528\u6237\u504f\u597d\u548c\u7a33\u5b9a\u4e8b\u5b9e\u3002<\/li>\n<li><strong>\u4e0a\u4e0b\u6587\u5173\u8054\uff1a<\/strong> \u65b0\u589e\u6d88\u606f\u65e0\u6cd5\u4e0e\u5df2\u6709\u4e0a\u4e0b\u6587\u5efa\u7acb\u5173\u8054\u3002<\/li>\n<\/ul>\n<p><strong>\u9009\u578b MemOS\uff1a<\/strong> \u5728 1540 \u4e2a\u95ee\u9898\u300110 \u4e2a\u6d4b\u8bd5\u7528\u6237\u7684\u8bc4\u6d4b\u4e2d\uff0c\u7efc\u5408\u5f97\u5206 74.33%\uff0c\u5355\u8df3\u4e0e\u591a\u8df3\u8868\u73b0\u5747\u8fbe\u6807\uff08\u8bc4\u6d4b\u4ec5\u4f5c\u9009\u578b\u53c2\u8003\uff0c\u4e0d\u4ee3\u8868\u751f\u4ea7 SLA\uff09\u3002<\/p>\n<p><strong>\u6574\u4f53\u67b6\u6784\uff1a<\/strong> \u540e\u7aef\u57fa\u4e8e Spring Boot 3 \u548c Java 17\uff0cAgent \u7f16\u6392\u91c7\u7528 AgentScope\u3002\u65b0\u5efa Agent \u9ed8\u8ba4\u5c06 longMemoryProvider \u8bbe\u4e3a MEMOS\uff0c\u4f46 openLongMemory \u9ed8\u8ba4\u5173\u95ed\uff1b\u5f00\u542f\u540e\uff0c\u8bf7\u6c42\u5f00\u59cb\u65f6\u77ed\u671f\u4f1a\u8bdd\u5386\u53f2\u548c\u957f\u671f\u8bb0\u5fc6\u5e76\u884c\u52a0\u8f7d\uff0c\u4f1a\u8bdd\u7ed3\u675f\u540e\u7531 onSessionEndAsync \u5f02\u6b65\u5b8c\u6210\u7b5b\u9009\u3001\u53bb\u91cd\u548c\u957f\u671f\u6c89\u6dc0\u3002\u77ed\u671f\u8bb0\u5fc6\u4ee5 MySQL \u4e3a\u6301\u4e45\u5316\u5e95\u5ea7\u3001Redis \u4e3a\u70ed\u70b9\u7f13\u5b58\uff0c\u957f\u671f\u8bb0\u5fc6\u4ee5 MemOS \u4e3a\u4e3b\u8def\u5f84\uff0c\u540c\u65f6\u4fdd\u7559 MySQL\/Mem0 \u8def\u7531\u4f5c\u4e3a\u517c\u5bb9\u8def\u5f84\u3002<\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215519\" alt=\"\" title=\"\"><\/p>\n<p><strong>\u672c\u6587\u53ea\u5c55\u5f00\u8bb0\u5fc6\u6a21\u5757\u7684\u5b9e\u73b0\uff1a<\/strong> \u5305\u62ec\u56db\u5c42\u8bb0\u5fc6\u6a21\u578b\u3001\u77ed\u671f\u5386\u53f2\u7684\u8bfb\u53d6\u4e0e\u5199\u5165\u3001MemOS \u7684\u6309 scope \u68c0\u7d22\uff0c\u4ee5\u53ca\u4f1a\u8bdd\u7ed3\u675f\u540e\u7684\u5f02\u6b65\u6c89\u6dc0\u3002<\/p>\n<h2>\u4e8c\u3001\u8bb0\u5fc6\u67b6\u6784\u6982\u89c8<\/h2>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215520\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215521\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<h3>Agent \u56db\u5c42\u8bb0\u5fc6\u6a21\u578b<\/h3>\n<p>\u56db\u5c42\u5206\u522b\u5bf9\u5e94\u4e0d\u540c\u7684\u751f\u547d\u5468\u671f\uff1aWorking Memory \u53ea\u670d\u52a1\u5f53\u524d\u4e00\u6b65\u63a8\u7406\uff1bSession Memory \u4fdd\u5b58\u4f1a\u8bdd\u5185\u7684\u6d88\u606f\u5386\u53f2\uff1bUser Memory \u8bb0\u5f55\u8de8 Agent \u5171\u4eab\u7684\u504f\u597d\u548c\u7a33\u5b9a\u4e8b\u5b9e\uff0c\u5bf9\u5e94 MemOS \u7684 user_profile\uff1bAgent Memory \u4fdd\u5b58\u67d0\u4e2a Agent \u7684\u4efb\u52a1\u7ecf\u9a8c\u548c\u534f\u4f5c\u7ea6\u5b9a\uff0c\u5bf9\u5e94 agent_{agentId}\u3002\u4f1a\u8bdd\u7ed3\u675f\u540e\uff0c\u65b0\u589e\u6d88\u606f\u7ecf\u8fc7\u5224\u65ad\u548c\u53bb\u91cd\uff0c\u518d\u4ece Session \u5c42\u6c89\u6dc0\u5230 User \u6216 Agent \u5c42\u3002<\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215522\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>Agent \u56db\u5c42\u8bb0\u5fc6\u6a21\u578b\uff1aWorking\u3001Session\u3001User \u4e0e Agent Memory \u7684\u8bfb\u53d6\u3001\u4f5c\u7528\u57df\u548c\u5f02\u6b65\u6c89\u6dc0\u94fe\u8def\u3002<\/p>\n<h4>\u8bb0\u5fc6\u7c7b\u578b<\/h4>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215523\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p><strong>\u56db\u5c42\u6a21\u578b\u4e0e MemOS \u7c7b\u578b\u662f\u4e24\u5957\u5206\u7c7b\u7ef4\u5ea6\uff1a<\/strong> \u56db\u5c42\u6a21\u578b\u63cf\u8ff0\u4fe1\u606f\u7684\u751f\u547d\u5468\u671f\u548c\u4f5c\u7528\u57df\uff1bMemOS \u7684 text_mem\u3001pref_mem\u3001skill_mem\u3001tool_mem \u63cf\u8ff0\u8bb0\u5fc6\u5185\u5bb9\u5f62\u6001\uff0c\u4e0d\u80fd\u76f4\u63a5\u4e0e\u56db\u5c42\u4e00\u4e00\u5bf9\u5e94\u3002<\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215524\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p><strong>\u5f53\u524d\u8def\u7531\u884c\u4e3a\uff1a<\/strong> longMemoryProvider \u672a\u914d\u7f6e\u3001Agent \u4e0d\u5b58\u5728\u6216\u8bfb\u53d6\u914d\u7f6e\u5f02\u5e38\u65f6\uff0cMemoryRpcServiceImpl \u9009\u62e9 MySQL\uff1b\u660e\u786e\u914d\u7f6e\u4e3a MEMOS \u6216 Mem0 \u65f6\u624d\u8fdb\u5165\u5bf9\u5e94 Provider\u3002MemOS \u67e5\u8be2\u5f02\u5e38\u7531 Provider \u81ea\u8eab\u8bb0\u5f55\u65e5\u5fd7\u5e76\u8fd4\u56de\u7a7a\u7ed3\u679c\uff0c\u5f53\u524d\u4e0d\u4f1a\u81ea\u52a8\u5207\u6362\u5230 MySQL\u3002<\/p>\n<h4>\u8bb0\u5fc6\u52a0\u8f7d\u6d41\u7a0b<\/h4>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215525\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p><strong>\u4e00\u6b21\u8bf7\u6c42\u7684\u8bb0\u5fc6\u8def\u5f84\u53ef\u4ee5\u6982\u62ec\u4e3a\uff1a<\/strong> AgentExecutor#execute \u89e3\u6790\u4e0a\u4e0b\u6587\u53c2\u6570\u540e\uff0c\u5728 memoryLoadExecutor \u4e2d\u5e76\u884c\u542f\u52a8\u77ed\u671f\u8bb0\u5fc6\u548c\u957f\u671f\u8bb0\u5fc6 Future\u3002\u77ed\u671f\u94fe\u8def\u8bfb\u53d6 ConversationMemory\uff1b\u957f\u671f\u94fe\u8def\u8c03\u7528 queryMemory\uff0c\u7531 MemoryRpcServiceImpl \u6309 Agent \u914d\u7f6e\u9009\u62e9 MEMOS\u3001Mem0 \u6216 MySQL\u3002<\/p>\n<ul>\n<li>\u957f\u671f\u8bb0\u5fc6\u68c0\u7d22\u8fd4\u56de\u540e\uff0c\u5e73\u53f0\u6309 user_profile \u4e0e agent \u5206\u7ec4\uff0c\u8fc7\u6ee4\u654f\u611f\u6216\u4f4e\u76f8\u5173\u5185\u5bb9\uff0c\u5e76\u9650\u5236\u6bcf\u4e2a scope \u7684\u6761\u6570\u3002<\/li>\n<li>\u968f\u540e\u4ee5\u56fa\u5b9a tokens \u4e3a\u9ed8\u8ba4\u9884\u7b97\uff0c\u4f18\u5148\u6ee1\u8db3\u7528\u6237\u753b\u50cf\uff0c\u518d\u628a\u5269\u4f59\u9884\u7b97\u5206\u914d\u7ed9 Agent \u4e13\u5c5e\u8bb0\u5fc6\u3002<\/li>\n<li>\u6700\u7ec8\u7ed3\u679c\u5199\u5165 AgentContext\uff0c\u4e0e\u77ed\u671f\u6d88\u606f\u4e00\u8d77\u53c2\u4e0e\u540e\u7eed\u6a21\u578b\u8c03\u7528\uff1b\u4f1a\u8bdd\u7ed3\u675f\u540e\u518d\u5f02\u6b65\u89e6\u53d1\u957f\u671f\u8bb0\u5fc6\u6c89\u6dc0\u548c\u4e0a\u4e0b\u6587\u6458\u8981\u3002<\/li>\n<\/ul>\n<p><strong>\u5b9e\u73b0\u8fb9\u754c\uff1a<\/strong> \u5e73\u53f0\u7684 ConversationMemory \u8d1f\u8d23\u4f1a\u8bdd\u5386\u53f2\u8bfb\u53d6\u548c\u7a97\u53e3\u88c1\u526a\uff1bAgentScope Harness \u7684 state store \u8d1f\u8d23\u4f1a\u8bdd\u72b6\u6001\u6301\u4e45\u5316\uff0c\u6709 Sandbox \u65f6\u4f7f\u7528\u5171\u4eab\u5de5\u4f5c\u533a\u6587\u4ef6\u5b58\u50a8\uff0c\u6ca1\u6709 Sandbox \u65f6\u56de\u9000\u5230\u5185\u5b58\u5b58\u50a8\u3002\u5f53\u524d ModelInvoker \u4e3b\u94fe\u8def\u6784\u9020 Harness \u6d88\u606f\u65f6\uff0c\u4ee5\u672c\u8f6e userMsg \u4e3a\u5165\u53e3\uff0c\u56e0\u6b64\u4e0d\u80fd\u7b80\u5355\u7406\u89e3\u4e3a Redis\/MySQL \u5386\u53f2\u4f1a\u88ab\u65e0\u6761\u4ef6\u76f4\u63a5\u62fc\u8fdb\u6bcf\u4e00\u6b21 AgentScope Prompt\u3002<\/p>\n<h4>\u77ed\u671f\u8bb0\u5fc6 vs \u957f\u671f\u8bb0\u5fc6<\/h4>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215526\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<h4>\u5173\u952e\u7ec4\u4ef6\u53ca\u65b9\u6cd5<\/h4>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215527\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<h2>\u4e09\u3001\u77ed\u671f\u8bb0\u5fc6\u52a0\u8f7d\u8be6\u60c5<\/h2>\n<p>\u77ed\u671f\u8bb0\u5fc6\uff08Session Memory\uff09\u4fdd\u5b58\u5f53\u524d\u4f1a\u8bdd\u4e2d\u6309\u65f6\u95f4\u6392\u5217\u7684\u5bf9\u8bdd\u5386\u53f2\uff0c\u662f\u6307\u4ee3\u6d88\u89e3\u548c\u591a\u8f6e\u63a8\u7406\u7684\u76f4\u63a5\u4e0a\u4e0b\u6587\u3002\u5b9e\u73b0\u91cd\u70b9\u662f\u8bfb\u53d6\u65f6\u5ef6\u3001Redis\/MySQL \u56de\u9000\u4ee5\u53ca Token \u7a97\u53e3\u63a7\u5236\u3002<\/p>\n<p><strong>\u52a0\u8f7d\u6d41\u7a0b\u56fe<\/strong><\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215528\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p><strong>\u8c03\u7528\u94fe\u8bf4\u660e\uff1a<\/strong><\/p>\n<ul>\n<li>AgentExecutor \u4ece AgentContext \u83b7\u53d6 AgentConfig \u2192 ModelBindConfigDto \u2192 contextRounds\u3002<\/li>\n<li>AgentExecutor \u8c03\u7528 chatMemory.get(conversationId, contextRounds * 3)\u3002<\/li>\n<li>chatMemory \u662f ConversationMemory \u63a5\u53e3\uff0c\u7531 ConversationApplicationServiceImpl \u5b9e\u73b0\u3002<\/li>\n<li>\u5b9e\u73b0\u7c7b\u4f18\u5148\u4ece Redis \u8bfb\u53d6\uff0c\u5931\u8d25\u5219\u4ece MySQL \u56de\u9000\u3002<\/li>\n<\/ul>\n<h3>\u5173\u952e\u5b9e\u73b0<\/h3>\n<p>\u5b8c\u6574\u5b9e\u73b0\u8fd8\u5305\u62ec\u6d88\u606f\u7c7b\u578b\u8f6c\u6362\u3001system \u6d88\u606f\u62c6\u5206\u53ca\u5de5\u5177\u8c03\u7528\u4fe1\u606f\u5904\u7406\u3002\u4e0b\u9762\u53ea\u4fdd\u7559&#8221;\u8bfb\u53d6 \u2192 \u4ea4\u66ff\u6821\u9a8c \u2192 Token \u7a97\u53e3\u5224\u65ad&#8221;\u7684\u4e3b\u8def\u5f84\uff0c\u4fbf\u4e8e\u7406\u89e3\u77ed\u671f\u8bb0\u5fc6\u5982\u4f55\u5f62\u6210\u6a21\u578b\u4e0a\u4e0b\u6587\u3002<\/p>\n<pre><code class=\"Java\">\/\/ DTO \u5df2\u8f6c\u6362\u4e3a Message\uff0csystem\/tool \u6d88\u606f\u5df2\u62c6\u5206\ntrimAlternationFromEnd(chatMsgs);\n\nint windowSize = MAX_TOKEN_WINDOW_SIZE - SUMMARY_TOKEN_BUDGET;\nint totalTokens = 0, recentTokens = 0;\nboolean overLimit = false;\nList&lt;Message&gt; recentWindow = new ArrayList&lt;&gt;();\n\nfor (int i = chatMsgs.size() - 1; i &gt;= 0; i--) {\n    Message message = chatMsgs.get(i);\n    int tokens = TikTokensUtil.tikTokensCount(message.getText());\n    totalTokens += tokens;\n    if (!overLimit &amp;&amp; recentTokens + tokens &lt;= windowSize) {\n        recentWindow.add(0, message);\n        recentTokens += tokens;\n    } else {\n        overLimit = true;\n    }\n}\n\nif (totalTokens &lt;= MAX_TOKEN_WINDOW_SIZE) {\n    removeLeadingAssistant(chatMsgs);\n    return mergeSystemAndChat(systemMsgs, chatMsgs);\n}\n\nremoveLeadingAssistant(recentWindow);\nString summaryMd = iMemoryRpcService.getConversationSummaryMd(Long.parseLong(cid));\nif (StringUtils.isNotBlank(summaryMd)) {\n    recentWindow.add(0, new SystemMessage(summaryMd));\n}\nreturn recentWindow;<\/code><\/pre>\n<p>Redis \u4f18\u5148\u8bfb\u53d6\uff0c\u7c7b\u8bf4\u660e\uff1aConversationApplicationServiceImpl#getMessagesFromCache \u5148\u8bfb\u53d6 Redis List\uff0c\u547d\u4e2d\u540e\u628a JSON \u8f6c\u4e3a ChatMessageDto\uff0c\u5e76\u7ffb\u8f6c\u4e3a oldest-first\uff1b\u672a\u547d\u4e2d\u6216\u8bfb\u53d6\u5f02\u5e38\u5219\u67e5\u8be2 MySQL\uff0c\u518d\u6309\u5012\u5e8f leftPush \u56de\u5199\uff0c\u8bbe\u7f6e CACHE_TTL_SECONDS\uff0c\u5e76\u7528 rightPop \u6309 MAX_CACHED_MESSAGES \u6dd8\u6c70\u6700\u65e7\u6d88\u606f\u3002\u9010\u6761\u89e3\u6790\u548c\u5f02\u5e38\u65e5\u5fd7\u5c5e\u4e8e\u9632\u5fa1\u6027\u4ee3\u7801\uff0c\u8fd9\u91cc\u4e0d\u5c55\u5f00\u3002<\/p>\n<h3>Redis \u5b58\u50a8\u7ed3\u6784\u5b9e\u73b0\u7ec6\u8282<\/h3>\n<p>\u4f7f\u7528 leftPush \u5199\u5165\uff0c\u6700\u65b0\u6d88\u606f\u5728 index 0\uff1b\u5f53\u524d\u5b9e\u73b0\u4f7f\u7528 range(0, Long.MAX_VALUE) \u8bfb\u53d6 Redis \u5217\u8868\uff0c\u518d\u5728\u5e94\u7528\u5c42\u505a\u7a97\u53e3\u88c1\u526a\uff1b\u4f7f\u7528 rightPop \u79fb\u9664\u6700\u65e7\u6d88\u606f \u9700\u8981\u6ce8\u610f\uff0cConversationMemory#get(String, int) \u7684 lastN \u53c2\u6570\u5f53\u524d\u672a\u53c2\u4e0e Redis \u7684 range \u8fb9\u754c\u8ba1\u7b97\uff1b\u5b9e\u9645\u8bfb\u53d6\u8303\u56f4\u7531 Redis \u5217\u8868\u5185\u5bb9\u548c\u540e\u7eed Token \u7a97\u53e3\u5171\u540c\u51b3\u5b9a\u3002Redis \u53ea\u627f\u62c5\u70ed\u70b9\u7f13\u5b58\uff0cMySQL \u4ecd\u662f\u51b7\u542f\u52a8\u56de\u6e90\u548c\u6301\u4e45\u5316\u515c\u5e95\u3002<\/p>\n<h3>Token \u7a97\u53e3\u63a7\u5236\u7b56\u7565<\/h3>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215529\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<h2>\u56db\u3001\u77ed\u671f\u8bb0\u5fc6\u5199\u5165\u8be6\u60c5<\/h2>\n<p><strong>\u5199\u5165\u65f6\u5e8f\u56fe<\/strong><\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215530\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p><strong>\u53cc\u5199\u7684\u610f\u4e49&#8212;&#8212;MySQL \uff1a<\/strong> \u6301\u4e45\u5316\u515c\u5e95\u9632\u6b62\u6570\u636e\u4e22\u5931\u3002<strong>Redis\uff1a<\/strong> \u9ad8\u6027\u80fd\u8bfb\u53d6\u652f\u6491\u5b9e\u65f6\u5bf9\u8bdd\u3002<strong>\u56de\u9000\u673a\u5236\uff1a<\/strong> Redis \u5931\u8d25\u65f6\u4ecd\u53ef\u4ece MySQL \u56de\u9000\u8bfb\u53d6\u3002<\/p>\n<pre><code>messages.forEach(message -&gt; {\n    String conversationId0 = conversationId;\n    if (conversationId0.startsWith(&quot;agent:&quot;)) {\n        \/\/ \u5b50 Agent \u7684\u975e ChatMessage \u4e0d\u5199\u5165\u4e3b\u4f1a\u8bdd\uff0c\u907f\u514d\u865a\u62df\u4f1a\u8bdd\u6c61\u67d3\u4e3b\u94fe\u8def\u3002\n        if (message instanceof ChatMessageDto) {\n            conversationId0 = conversationId.replace(&quot;agent:&quot;, &quot;&quot;);\n        } else {\n            return;\n        }\n    }\n    ChatMessageDto chatMessage = ...; \/\/ \u7c7b\u578b\u8f6c\u6362\u3001\u6e05\u6d17\u6587\u672c\u5e76\u8865\u9f50\u79df\u6237\u5b57\u6bb5\n    ConversationMessage conversationMessage = ...;\n    \/\/ \u5148\u843d MySQL\uff0cRedis \u53ea\u4f5c\u4e3a\u53ef\u5931\u6548\u7684\u70ed\u70b9\u7f13\u5b58\u3002\n    Long messageId = TenantFunctions.callWithTenantId(chatMessage.getTenantId(),\n        () -&gt; conversationDomainService.addConversationMessage(conversationMessage));\n    chatMessage.setIndex(messageId);\n    try {\n        String key = generateConversationKey(conversationId0);\n        redisUtil.leftPush(key, JSON.toJSONString(chatMessage));\n        redisUtil.expire(key, CACHE_TTL_SECONDS);\n        long size = redisUtil.size(key);\n        \/\/ \u6700\u65b0\u6d88\u606f\u5728\u8868\u5934\uff0c\u8d85\u51fa 200 \u6761\u65f6\u4ece\u5c3e\u90e8\u6dd8\u6c70\u6700\u65e7\u6d88\u606f\u3002\n        if (size &gt; MAX_CACHED_MESSAGES) {\n            redisUtil.rightPop(key);\n        }\n    } catch (Exception e) {\n        \/\/ \u7f13\u5b58\u5931\u8d25\u4e0d\u56de\u6eda\u5df2\u5b8c\u6210\u7684 MySQL \u5199\u5165\uff0c\u8bfb\u53d6\u65f6\u4f1a\u56de\u6e90\u6570\u636e\u5e93\u3002\n        log.warn(&quot;Failed to cache message to Redis, conversationId={}&quot;, conversationId0, e);\n    }\n});\n<\/code><\/pre>\n<p>\u77ed\u671f\u6d88\u606f\u5199\u5165\u540e\uff0conSessionEndAsync \u8fd8\u4f1a\u68c0\u67e5\u4f1a\u8bdd\u6458\u8981\uff1a\u5f53\u672a\u88ab\u6458\u8981\u8986\u76d6\u7684\u6d88\u606f\u8fbe\u5230 20 \u6761\u624d\u89e6\u53d1\u6458\u8981\u751f\u6210\uff0c\u6458\u8981\u6ce8\u5165\u9884\u7b97\u7ea6 2000 tokens\uff0c\u5e76\u5728 Redis \u7f13\u5b58 1 \u5c0f\u65f6\u3002\u8fd9\u6837\u505a\u628a\u9ad8\u9891\u5bf9\u8bdd\u5199\u5165\u4e0e\u4f4e\u9891\u6458\u8981\u5408\u5e76\u62c6\u5f00\uff0c\u907f\u514d\u6bcf\u8f6e\u90fd\u8c03\u7528\u6458\u8981\u6a21\u578b\u3002<\/p>\n<h2>\u4e94\u3001\u957f\u671f\u8bb0\u5fc6\u52a0\u8f7d\u5b9e\u73b0\u8be6\u89e3<\/h2>\n<p><strong>\u52a0\u8f7d\u65f6\u5e8f\u56fe<\/strong><\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215531\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<h3>\u5e76\u884c\u52a0\u8f7d\u8bbe\u8ba1<\/h3>\n<p>\u5728 Agent \u6267\u884c\u5165\u53e3 AgentExecutor#execute \u4e2d\uff0c\u6211\u4eec\u91c7\u7528 CompletableFuture \u5b9e\u73b0\u77ed\u671f\u8bb0\u5fc6\u548c\u957f\u671f\u8bb0\u5fc6\u7684\u5e76\u884c\u52a0\u8f7d\uff1a<\/p>\n<pre><code>final int finalContextRounds = contextRounds;\nCompletableFuture&lt;List&lt;Message&gt;&gt; contextMessagesFuture = CompletableFuture.supplyAsync(() -&gt; {\n    \/\/ contextRounds=0 \u662f\u5408\u6cd5\u914d\u7f6e\uff0c\u76f4\u63a5\u8df3\u8fc7\u77ed\u671f\u5386\u53f2\u8bfb\u53d6\u3002\n    if (finalContextRounds &lt;= 0) {\n        return new ArrayList&lt;Message&gt;();\n    }\n    return new ArrayList&lt;&gt;(\n        chatMemory.get(agentContext.getConversationId(), finalContextRounds * 3));\n}, memoryLoadExecutor);\n\nCompletableFuture&lt;Map&lt;String, String&gt;&gt; longMemoryFuture = CompletableFuture.supplyAsync(() -&gt; {\n    if (agentContext.getAgentConfig().getOpenLongMemory() != AgentConfig.OpenStatus.Open) {\n        return Collections.emptyMap();\n    }\n    try {\n        AgentComponentConfigDto modelComponentConfig =\n            agentContext.getAgentConfig().getModelComponentConfig();\n        \/\/ queryMemory \u9700\u8981\u7ed1\u5b9a\u6a21\u578b\u7684 targetId\uff0c\u672a\u7ed1\u5b9a\u65f6\u4e0d\u53d1\u8d77\u957f\u671f\u68c0\u7d22\u3002\n        if (modelComponentConfig == null || modelComponentConfig.getTargetId() == null) {\n            return Collections.emptyMap();\n        }\n        boolean justKeywordMatch = resolveJustKeywordMatch(agentContext);\n        \/\/ originalMessage \u662f\u4e3b\u67e5\u8be2\u8bcd\uff1b\u6b64\u5904 context \u4e3a\u7a7a\uff0c\u77ed\u671f\u5386\u53f2\u4e0d\u4f1a\u53cd\u5411\u589e\u5f3a\u672c\u6b21 query\u3002\n        return conversationApplicationService.queryMemory(\n            agentContext.getUser().getTenantId(), agentContext.getUser().getId(),\n            agentContext.getAgentConfig().getId(), modelComponentConfig.getTargetId(),\n            agentContext.getOriginalMessage(), &quot;&quot;, justKeywordMatch,\n            agentContext.isFilterSensitive());\n    } catch (Exception e) {\n        \/\/ \u957f\u671f\u8bb0\u5fc6\u662f\u589e\u5f3a\u80fd\u529b\uff0c\u67e5\u8be2\u5931\u8d25\u65f6\u8ba9\u4e3b\u5bf9\u8bdd\u7ee7\u7eed\u3002\n        log.warn(&quot;\u67e5\u8be2\u957f\u671f\u8bb0\u5fc6\u5931\u8d25&quot;, e);\n        return Collections.emptyMap();\n    }\n}, memoryLoadExecutor);\n\n\/\/ \u8fd9\u91cc\u624d\u662f\u5e76\u884c\u7ed3\u679c\u7684\u6c47\u5408\u70b9\uff0c\u4e3b\u6d41\u7a0b\u7b49\u5f85\u4e24\u6761\u8bb0\u5fc6\u94fe\u8def\u90fd\u5b8c\u6210\u3002\nagentContext.setContextMessages(contextMessagesFuture.join());\nMap&lt;String, String&gt; longMemoryMap = longMemoryFuture.join();\n<\/code><\/pre>\n<p><strong>\u8bbe\u8ba1\u8981\u70b9\uff1a<\/strong> \u4f7f\u7528\u4e13\u7528\u7ebf\u7a0b\u6c60 memoryLoadExecutor\uff0c\u907f\u514d ForkJoinPool.commonPool \u4e89\u62a2\uff1b\u957f\u671f\u8bb0\u5fc6\u4e0d\u963b\u585e\u77ed\u671f\u8bb0\u5fc6\uff0c\u7528\u7a7a context \u5148\u884c\u67e5\u8be2\u3002<\/p>\n<p><strong>\u8fb9\u754c\u4e0e\u964d\u7ea7\uff1a<\/strong> \u5173\u95ed openLongMemory \u65f6\u957f\u671f Future \u76f4\u63a5\u8fd4\u56de\u7a7a Map\uff1bAgent \u672a\u7ed1\u5b9a\u6a21\u578b\u65f6\u8df3\u8fc7\u957f\u671f\u68c0\u7d22\uff1b\u67e5\u8be2\u5f02\u5e38\u4e5f\u4f1a\u8bb0\u5f55 warning \u5e76\u8fd4\u56de\u7a7a\u7ed3\u679c\uff0c\u4e3b\u5bf9\u8bdd\u7ee7\u7eed\u6267\u884c\u3002\u5f53\u524d\u957f\u671f\u67e5\u8be2\u4ee5 originalMessage \u4f5c\u4e3a\u4e3b\u68c0\u7d22\u8bcd\uff0c\u548c\u77ed\u671f\u8bb0\u5fc6\u7684\u8bfb\u53d6\u4e92\u4e0d\u7b49\u5f85\uff0c\u56e0\u6b64\u5e76\u884c\u5e26\u6765\u7684\u662f\u6267\u884c\u91cd\u53e0\uff0c\u4e0d\u662f&#8221;\u77ed\u671f\u5386\u53f2\u5df2\u6ce8\u5165\u540e\u518d\u589e\u5f3a\u67e5\u8be2&#8221;\u3002<\/p>\n<h3>\u8bed\u4e49\u68c0\u7d22\u5b9e\u73b0<\/h3>\n<p>MemOS Search \u8bf7\u6c42\u4fdd\u7559\u4ee5\u4e0b\u53c2\u6570\uff1bcontext \u975e\u7a7a\u65f6\uff0c\u5e73\u53f0\u53ea\u53d6\u524d 200 \u4e2a\u5b57\u7b26\u62fc\u5230 userMessage \u540e\u4f5c\u4e3a query\u3002\u8c03\u7528\u94fe\u867d\u7136\u643a\u5e26 justKeywordSearch\uff0c\u4f46\u5f53\u524d MemosMemoryApplicationService \u672a\u636e\u6b64\u5207\u6362\u68c0\u7d22\u6a21\u5f0f\uff0c\u4ecd\u56fa\u5b9a\u8c03\u7528 MemOS Search\u3002<\/p>\n<pre><code>List&lt;String&gt; readableCubeIds = new ArrayList&lt;&gt;();\nreadableCubeIds.add(&quot;user_profile&quot;);\nif (agentId != null) {\n    readableCubeIds.add(&quot;agent_&quot; + agentId);\n}\n\nMemOSClient.SearchRequest searchRequest = new MemOSClient.SearchRequest();\n\/\/ \u4e00\u6b21 Search \u540c\u65f6\u8986\u76d6\u7528\u6237\u753b\u50cf\u548c\u5f53\u524d Agent \u7684\u8bb0\u5fc6 cube\u3002\nsearchRequest.setQuery(buildSearchQuery(userMessage, context));\nsearchRequest.setUserId(memOSUserId);\nsearchRequest.setTopK(DEFAULT_TOP_K);\nsearchRequest.setMode(&quot;fast&quot;);\nsearchRequest.setRelativity(0.45);\nsearchRequest.setDedup(&quot;mmr&quot;);\nsearchRequest.setReadableCubeIds(readableCubeIds);\nsearchRequest.setIncludePreference(true);\nsearchRequest.setPrefTopK(6);\n\nList&lt;MemOSMemory&gt; searchResults =\n    memOSClient.searchMemory(searchRequest).getMemories();\n\/\/ \u8f6c\u6362\u9636\u6bb5\u4f1a\u8fc7\u6ee4\u4f4e\u5206\u7ed3\u679c\u3001\u622a\u65ad\u5355\u6761\u5185\u5bb9\uff0c\u518d\u6309 score \u964d\u5e8f\u8fd4\u56de\u3002\nresult.addAll(convertToMemoryUnitDTOs(searchResults, tenantId, userId, agentId));\nresult.sort((a, b) -&gt; {\n    if (a.getScore() == null &amp;&amp; b.getScore() == null) return 0;\n    if (a.getScore() == null) return 1;\n    if (b.getScore() == null) return -1;\n    return Double.compare(b.getScore(), a.getScore());\n});\n<\/code><\/pre>\n<h3>\u641c\u7d22\u53c2\u6570\u8bf4\u660e\uff1a<\/h3>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215532\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>readableCubeIds \u5f53\u524d\u5305\u542b user_profile \u548c agent_{agentId}\uff1b\u540c\u65f6\u5f00\u542f preference \u68c0\u7d22\uff0cprefTopK=6 \u7528\u4e8e\u8865\u5145\u7528\u6237\u504f\u597d\u3002\u68c0\u7d22\u7ed3\u679c\u968f\u540e\u8fd8\u4f1a\u7ecf\u8fc7 score \/&lt; 0.3 \u8fc7\u6ee4\u548c\u5355\u6761 1000 \u5b57\u7b26\u622a\u65ad\uff0c\u907f\u514d\u4f4e\u76f8\u5173\u6216\u8fc7\u957f\u5185\u5bb9\u6324\u5360\u4e0a\u4e0b\u6587\u3002<\/p>\n<h3>Token Budget \u5206\u914d\u7b56\u7565<\/h3>\n<p>\u4ee5\u4e0b\u7247\u6bb5\u627f\u63a5 5.2 \u7684\u68c0\u7d22\u7ed3\u679c\uff0cuserProfileRaw \u4e0e agentMemoryRaw \u5206\u522b\u662f\u6309 scope \u6c47\u603b\u540e\u7684\u6587\u672c\u3002\u4e3a\u9632\u6b62\u8bb0\u5fc6\u6491\u7206 Agent \u4e0a\u4e0b\u6587\uff0c\u6211\u4eec\u8bbe\u8ba1\u4e86 Token Budget \u5206\u914d\u673a\u5236\u3002<\/p>\n<pre><code>int budget = DEFAULT_LONG_MEMORY_TOKEN_BUDGET; \/\/ 4000 tokens\nint userProfileRawTokens =\n    TikTokensUtil.tikTokensCount(userProfileRaw != null ? userProfileRaw : &quot;&quot;);\n\n\/\/ user_profile \u6700\u591a\u5360 60%\uff1b\u5b9e\u9645\u672a\u7528\u6ee1\u65f6\uff0c\u5269\u4f59\u9884\u7b97\u8ba9\u7ed9 Agent \u8bb0\u5fc6\u3002\nif (userProfileRawTokens &lt;= budget * 0.6) {\n    userProfile = userProfileRaw;\n    agentMemory = truncateLongMemory(agentMemoryRaw, budget - userProfileRawTokens);\n} else {\n    userProfile = truncateLongMemory(userProfileRaw, (int) (budget * 0.6));\n    \/\/ \u91cd\u65b0\u8ba1\u7b97\u622a\u65ad\u540e\u7684 token \u6570\uff0c\u907f\u514d\u628a\u622a\u65ad\u524d\u7684\u4f30\u7b97\u5e26\u5165\u5269\u4f59\u9884\u7b97\u3002\n    int userProfileTokens =\n        TikTokensUtil.tikTokensCount(userProfile != null ? userProfile : &quot;&quot;);\n    agentMemory = truncateLongMemory(agentMemoryRaw, budget - userProfileTokens);\n}\n\u622a\u65ad\u7b97\u6cd5\u91c7\u7528\u6309\u884c\u622a\u65ad\uff0c\u4fdd\u7559\u5b8c\u6574\u8bed\u4e49\uff1a\n\nString[] lines = longMemory.split(&quot;\/n&quot;, -1);\nfor (String line : lines) {\n    \/\/ \u6309\u884c\u7d2f\u8ba1 token\uff0c\u5c3d\u91cf\u4fdd\u7559\u4e00\u6761\u8bb0\u5fc6\u7684\u5b8c\u6574\u5185\u5bb9\u3002\n    int lineTokens = TikTokensUtil.tikTokensCount(line + &quot;\/n&quot;);\n    if (currentTokens + lineTokens &gt; budget) {\n        break;\n    }\n    truncated.append(line);\n    currentTokens += lineTokens;\n}\n<\/code><\/pre>\n<p>user_profile \u6700\u591a\u5360 60% \u9884\u7b97\uff1b\u5982\u679c\u5b9e\u9645\u5360\u7528\u66f4\u5c11\uff0c\u5269\u4f59\u7a7a\u95f4\u5206\u7ed9 Agent \u8bb0\u5fc6\u3002\u4e24\u7c7b\u5185\u5bb9\u90fd\u6309\u884c\u7d2f\u52a0 token\uff0c\u8fbe\u5230\u9884\u7b97\u540e\u505c\u6b62\u8ffd\u52a0\uff0c\u907f\u514d\u62c6\u6563\u5355\u6761\u8bb0\u5fc6\u3002<\/p>\n<h2>\u516d\u3001\u957f\u671f\u8bb0\u5fc6\u5199\u5165\u5b9e\u73b0\u8be6\u89e3<\/h2>\n<p><strong>\u5199\u5165\u65f6\u5e8f\u56fe<\/strong><\/p>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000048215533\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<h3>\u5199\u5165\u5165\u53e3\u4e0e\u53bb\u91cd<\/h3>\n<p>\u4f1a\u8bdd\u7ed3\u675f\u65f6\uff0c\u7cfb\u7edf\u89e6\u53d1\u8bb0\u5fc6\u5199\u5165\u6d41\u7a0b\uff0c\u9996\u5148\u4f7f\u7528 Redis Set \u8bb0\u5f55\u5df2\u5904\u7406\u6d88\u606f\u7684 hash \u5e76\u505a\u53bb\u91cd\u3002<\/p>\n<p><strong>\u7c7b\u8bf4\u660e\uff1a<\/strong> MemoryRpcServiceImpl \u8d1f\u8d23\u4f1a\u8bdd\u7ed3\u675f\u540e\u7684\u5199\u5165\u7f16\u6392\uff0conSessionEndAsync \u5148\u83b7\u53d6\u4f1a\u8bdd\u7ea7 Redis \u9501\uff0c\u518d\u7531 processSessionEnd \u6309\u6d88\u606f hash \u8fc7\u6ee4\u672c\u6b21\u65b0\u589e\u5185\u5bb9\u5e76\u63d0\u524d\u8bb0\u5f55\u5df2\u5904\u7406 hash\uff0c\u968f\u540e\u6839\u636e Agent \u914d\u7f6e\u9009\u62e9 provider\uff1aMemOS \u8def\u5f84\u5148\u8fdb\u884c LLM \u8bb0\u5fc6\u5224\u65ad\uff0c\u518d\u4ea4\u7ed9 MemoryPersistenceServiceImpl \u6301\u4e45\u5316\uff1bMySQL\u3001Mem0 \u8def\u5f84\u5219\u7ec4\u88c5\u5b8c\u6574\u4e0a\u4e0b\u6587\u548c\u6700\u65b0 user \u8f93\u5165\u540e\u8c03\u7528 createMemory\u3002\u8bb0\u5fc6\u5904\u7406\u5b8c\u6210\u540e\uff0c\u540c\u4e00\u5f02\u6b65\u7ebf\u7a0b\u7ee7\u7eed\u68c0\u67e5\u662f\u5426\u9700\u8981\u751f\u6210\u4e0a\u4e0b\u6587\u6458\u8981\u3002<\/p>\n<p><strong>\u8bbe\u8ba1\u8981\u70b9\uff1a<\/strong><\/p>\n<ul>\n<li>\u5206\u5e03\u5f0f\u9501\u9632\u6b62\u5e76\u53d1\u5904\u7406\u540c\u4e00\u4f1a\u8bdd\u3002<\/li>\n<li>MD5(role:content) \u751f\u6210\u6d88\u606f\u552f\u4e00\u6807\u8bc6\u3002<\/li>\n<li>TTL 7 \u5929\u81ea\u52a8\u6e05\u7406\u8fc7\u671f\u8bb0\u5f55\u3002<\/li>\n<\/ul>\n<p>onSessionEndAsync \u4f7f\u7528 10 \u5206\u949f\u7684\u4f1a\u8bdd\u9501\uff0c\u5df2\u5904\u7406\u6d88\u606f hash \u7684 TTL \u4e3a 7 \u5929\u3002hash \u4f1a\u5728 LLM \u5224\u65ad\u548c MemOS \u6301\u4e45\u5316\u4e4b\u524d\u5199\u5165\uff0c\u7528\u6765\u6321\u4f4f\u91cd\u590d\u7ed3\u675f\u4e8b\u4ef6\u3002\u4f46\u8fd9\u4e00\u5c42\u5c5e\u4e8e best-effort\uff1aRedis \u8bfb\u53d6\u5931\u8d25\u65f6\uff0c\u5f53\u524d\u5b9e\u73b0\u4f1a\u628a\u6574\u6bb5\u4f1a\u8bdd\u4f5c\u4e3a\u65b0\u589e\u5185\u5bb9\u7ee7\u7eed\u5904\u7406\uff1bhash \u5199\u5165\u5931\u8d25\u4e5f\u53ea\u8bb0\u5f55\u65e5\u5fd7\u3002\u5916\u90e8\u670d\u52a1\u5931\u8d25\u540e\u6ca1\u6709\u81ea\u52a8\u56de\u653e\uff0c\u56e0\u6b64\u8fd0\u884c\u4fa7\u9700\u8981\u540c\u65f6\u5173\u6ce8\u91cd\u590d\u5199\u5165\u548c\u5904\u7406\u672a\u5b8c\u6210\u4e24\u7c7b\u5f02\u5e38\u3002<\/p>\n<h3>LLM \u667a\u80fd\u5224\u65ad<\/h3>\n<p>\u5b8c\u6574 Prompt \u5b9a\u4e49\u4e86\u8bb0\u5fc6\u7c7b\u522b\u3001scope\u3001importance \u548c JSON \u8f93\u51fa\u7ea6\u675f\uff0c\u4e0b\u9762\u53ea\u4fdd\u7559\u65b0\u589e\u6d88\u606f\u6807\u8bb0\u4e0e\u6a21\u578b\u8c03\u7528\u4e3b\u7ebf\u3002judge \u4f1a\u5148\u8c03\u7528 LLM\uff1b\u8c03\u7528\u5f02\u5e38\u6216\u8fd4\u56de\u4e3a\u7a7a\u65f6\uff0c\u964d\u7ea7\u5230\u4ec5\u57fa\u4e8e\u65b0\u589e\u6d88\u606f\u7684\u89c4\u5219\u5224\u65ad\u3002LLM \u8fd4\u56de\u4e0d\u4e3a\u7a7a\u65f6\uff0c\u8fd8\u4f1a\u7edf\u4e00\u8865\u9f50\u7f3a\u7701\u5b57\u6bb5\u3001\u8fc7\u6ee4\u7a7a\u5185\u5bb9\uff0c\u5e76\u5c06\u5355\u6761\u8bb0\u5fc6\u622a\u65ad\u5230 200 \u5b57\u7b26\u3002<\/p>\n<pre><code>private MemoryJudgeResult judgeByLLM(Long tenantId, Long modelId,\n        List&lt;MemoryMessage&gt; fullContext, List&lt;MemoryMessage&gt; newMessages) {\n    Set&lt;String&gt; newMessageKeys = newMessages.stream()\n        .map(m -&gt; (m.getRole() != null ? m.getRole() : &quot;user&quot;)\n            + &quot;:&quot; + (m.getContent() != null ? m.getContent() : &quot;&quot;))\n        .collect(Collectors.toSet());\n\n    StringBuilder content = new StringBuilder(&quot;## \u5b8c\u6574\u5bf9\u8bdd\u4e0a\u4e0b\u6587\/n\/n&quot;);\nfor (MemoryMessage message : fullContext) {\n        String role = message.getRole() != null ? message.getRole() : &quot;user&quot;;\n        String text = message.getContent() != null ? message.getContent() : &quot;&quot;;\n        content.append(newMessageKeys.contains(role + &quot;:&quot; + text)\n                ? &quot;[[NEW] &quot; : &quot;[&quot;)\n            .append(role).append(&quot;]: &quot;).append(text).append(&quot;\/n&quot;);\n    }\n\n    MemoryJudgeResult result = iModelRpcService.call(\n        tenantId, modelId, JUDGE_SYSTEM_PROMPT, content.toString(),\nnew ParameterizedTypeReference&lt;MemoryJudgeResult&gt;() {});\nreturn result == null ? null : validateAndFixResult(result);\n}\n<\/code><\/pre>\n<p><strong>\u5224\u65ad\u8981\u70b9\uff1a<\/strong><\/p>\n<ul>\n<li>\u6309 role:content \u751f\u6210\u6d88\u606f key \u5e76\u6807\u8bb0\u91cd\u70b9\u5185\u5bb9\uff0c\u76f8\u540c\u5185\u5bb9\u7684\u5386\u53f2\u6d88\u606f\u4e5f\u53ef\u80fd\u4e00\u5e76\u547d\u4e2d\u3002<\/li>\n<li>\u6309 5 \u7c7b\u4fe1\u606f\u5b9a\u4e49 importance \u533a\u95f4\uff081-10\uff09\u3002<\/li>\n<li>\u660e\u786e scope \u5f52\u5c5e\u89c4\u5219\u3002<\/li>\n<\/ul>\n<h3>\u53bb\u91cd\u4e0e\u51b2\u7a81\u5904\u7406<\/h3>\n<p>\u5728\u6301\u4e45\u5316\u524d\u8fdb\u884c\u672c\u5730\u76f8\u4f3c\u5ea6\u53bb\u91cd\uff0c\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u5199\u5165\uff1a<strong>\u7c7b\u8bf4\u660e\uff1a<\/strong> MemoryPersistenceServiceImpl#calculateSimilarity \u6309 exact\u3001contains\u3001\u5b57\u7b26\u7ea7 Jaccard\uff08\u9608\u503c 0.7\uff09\u548c\u77ed\u6587\u672c Levenshtein\uff08\u9608\u503c 0.8\uff09\u4f9d\u6b21\u5224\u65ad\uff0c\u76f8\u4f3c\u5373\u6807\u8bb0\u4e3a\u91cd\u590d\uff1b\u7a7a\u503c\u6216\u672a\u8fbe\u5230\u9608\u503c\u5219\u8fd4\u56de none\u3002\u5b83\u53ea\u8d1f\u8d23\u540c\u6279\u6b21\u7684\u672c\u5730\u9884\u53bb\u91cd\uff0c\u8de8\u5386\u53f2\u8bb0\u5fc6\u7684\u51b2\u7a81\u4ecd\u4ea4\u7ed9\u540e\u7eed\u51b2\u7a81\u670d\u52a1\u5904\u7406\u3002<\/p>\n<p>batchPersist \u5b8c\u6210\u672c\u5730\u53bb\u91cd\u540e\uff0c\u5148\u6309 memCubeId \u5206\u7ec4\uff0c\u518d\u8c03\u7528 batchDetectConflict \u83b7\u53d6\u6bcf\u6761\u5019\u9009\u8bb0\u5fc6\u7684\u51b2\u7a81\u7ed3\u679c\u3002\u4e0b\u9762\u53ea\u4fdd\u7559\u9010\u6761\u51b3\u5b9a&#8221;\u5199\u5165\u65b0\u8bb0\u5fc6\u3001\u8df3\u8fc7\uff0c\u6216\u8bb0\u5f55\u5f85\u5931\u6548\u65e7\u8bb0\u5fc6&#8221;\u7684\u6838\u5fc3\u5faa\u73af\uff1a<\/p>\n<pre><code>for (int i = 0; i &lt; memoryList.size(); i++) {\n    MemoryToSave memory = memoryList.get(i);\n    MemoryConflictResult conflict = i &lt; conflictResults.size()\n        ? conflictResults.get(i) : MemoryConflictResult.noConflict();\n\n    if (!conflict.isHasConflict()) {\n        messagesToStore.add(createMessage(memory.getContent()));\n        continue;\n    }\n\n    ConflictResolutionResult resolution =\n        memoryConflictService.resolveConflict(\n            tenantId, memOSUserId, memCubeId,\n            memory.getContent(), conflict, modelId);\n    if (resolution.isShouldStoreNew()) {\n        messagesToStore.add(createMessage(memory.getContent()));\n        if (CollectionUtils.isNotEmpty(resolution.getMemoryIdsToExpire())) {\n            memoryIdsToDelete.addAll(resolution.getMemoryIdsToExpire());\n        }\n    }\n}\n<\/code><\/pre>\n<p>\u8fd9\u91cc\u7684&#8221;\u6279\u91cf&#8221;\u4e3b\u8981\u6307\u6309 memCubeId \u5206\u7ec4\u3001\u590d\u7528\u4e00\u6279\u5f85\u5199\u5165\u5185\u5bb9\uff1b\u51b2\u7a81\u670d\u52a1\u7684\u6279\u91cf\u65b9\u6cd5\u5728\u5b9e\u73b0\u5185\u90e8\u4ecd\u9010\u6761\u8c03\u7528\u68c0\u6d4b\u63a5\u53e3\uff0c\u518d\u9010\u6761\u51b3\u5b9a\u4fdd\u7559\u65b0\u8bb0\u5fc6\u3001\u8df3\u8fc7\u6216\u6807\u8bb0\u65e7\u8bb0\u5fc6\u3002\u56e0\u6b64\u5b83\u51cf\u5c11\u4e86\u5206\u7ec4\u548c\u7f16\u6392\u5f00\u9500\uff0c\u4f46\u4e0d\u80fd\u7b49\u540c\u4e8e\u4e00\u6b21\u7f51\u7edc\u8bf7\u6c42\u5b8c\u6210\u5168\u90e8\u51b2\u7a81\u5224\u65ad\u3002<\/p>\n<h3>\u5148\u5199\u540e\u5220\u7b56\u7565<\/h3>\n<p>\u4e3a\u907f\u514d\u6570\u636e\u4e22\u5931\uff0c\u91c7\u7528&#8221;\u5148\u5199\u65b0\u8bb0\u5fc6\uff0c\u540e\u5220\u65e7\u8bb0\u5fc6&#8221;\u7b56\u7565\u3002<\/p>\n<p><strong>\u7c7b\u8bf4\u660e\uff1a<\/strong> MemoryPersistenceServiceImpl#batchPersist \u6309 memCubeId \u7ec4\u88c5 MemOS \u7684 AddMemoryRequest\uff0c\u5199\u5165 userId\u3001writableCubeIds \u548c messages\uff0c\u5e76\u4ee5 async\u3001fine \u6a21\u5f0f\u8c03\u7528 addMemory\u3002\u53ea\u6709\u8fd4\u56de\u7ed3\u679c\u4e2d\u5305\u542b\u65b0\u589e\u8bb0\u5fc6\u65f6\uff0c\u624d\u628a\u51b2\u7a81\u65e7\u8bb0\u5fc6 ID \u4ea4\u7ed9 deleteMemories\uff1b\u5220\u9664\u5f02\u5e38\u53ea\u8bb0\u5f55 warning\uff0c\u5df2\u7ecf\u5199\u5165\u7684\u65b0\u8bb0\u5fc6\u7ee7\u7eed\u4fdd\u7559\u3002<\/p>\n<p>\u8fd9\u662f\u4e00\u79cd&#8221;\u5199\u5165\u4f18\u5148&#8221;\u7684\u98ce\u9669\u63a7\u5236\uff0c\u800c\u4e0d\u662f\u4e8b\u52a1\u7ea7\u4e00\u81f4\u6027\uff1aMemOS \u662f\u5916\u90e8 HTTP \u670d\u52a1\uff0c\u5e73\u53f0\u65e0\u6cd5\u7528\u672c\u5730\u4e8b\u52a1\u540c\u65f6\u5305\u4f4f\u65b0\u589e\u548c\u5220\u9664\u3002\u5f53\u524d\u5220\u9664\u5931\u8d25\u53ea\u8bb0\u5f55 warning\uff0c\u5c5e\u4e8e best-effort\uff1b\u65e7\u8bb0\u5fc6\u53ef\u80fd\u6682\u65f6\u4fdd\u7559\uff0c\u540e\u7eed\u68c0\u7d22\u6216\u4e0b\u4e00\u6b21\u51b2\u7a81\u5904\u7406\u518d\u8fdb\u884c\u6e05\u7406\u3002<\/p>\n<h2>\u4e03\u3001\u6838\u5fc3\u8bbe\u8ba1\u4e0e\u8fd0\u884c\u89c2\u6d4b<\/h2>\n<p>\u8fd9\u5957\u5b9e\u73b0\u628a\u8bb0\u5fc6\u5904\u7406\u62c6\u6210\u4e24\u6761\u72ec\u7acb\u94fe\u8def\uff1a\u8bf7\u6c42\u524d\u5e76\u884c\u52a0\u8f7d\u77ed\u671f\u5386\u53f2\u548c\u957f\u671f\u8bb0\u5fc6\uff0c\u4f1a\u8bdd\u7ed3\u675f\u540e\u5f02\u6b65\u5b8c\u6210\u7b5b\u9009\u3001\u53bb\u91cd\u548c\u6301\u4e45\u5316\u3002\u6838\u5fc3\u7b56\u7565\u96c6\u4e2d\u5728\u56db\u70b9\uff1a<\/p>\n<ul>\n<li><strong>\u5e76\u884c\u52a0\u8f7d\uff1a<\/strong> \u77ed\u671f\u8bb0\u5fc6\u548c\u957f\u671f\u8bb0\u5fc6\u63d0\u4ea4\u5230\u540c\u4e00\u4e2a\u4e13\u7528\u7ebf\u7a0b\u6c60\uff0c\u4e3b\u6d41\u7a0b\u5728 join \u5904\u6c47\u5408\u3002<\/li>\n<li><strong>\u65b0\u589e\u6d88\u606f\u6807\u8bb0\uff1a<\/strong> \u4f7f\u7528 [[NEW]] \u6807\u8bb0\u672c\u6b21\u65b0\u589e\u6d88\u606f\uff0c\u8ba9 LLM \u501f\u52a9\u5b8c\u6574\u4e0a\u4e0b\u6587\u63d0\u53d6\u65b0\u4fe1\u606f\u3002<\/li>\n<li><strong>\u9884\u7b97\u63a7\u5236\uff1a<\/strong> \u77ed\u671f\u5386\u53f2\u91c7\u7528\u6ed1\u52a8\u7a97\u53e3\u5e76\u9884\u7559\u6458\u8981\u7a7a\u95f4\uff0c\u957f\u671f\u8bb0\u5fc6\u6309 scope \u5206\u7ec4\u540e\u5206\u914d\u56fa\u5b9a tokens\u3002<\/li>\n<li><strong>\u53ef\u9760\u5199\u5165\uff1a<\/strong> Redis \u9501\u548c hash \u8d1f\u8d23\u5e42\u7b49\uff0cMemOS \u4fa7\u5148\u5199\u65b0\u8bb0\u5fc6\u3001\u518d\u5c3d\u529b\u5220\u9664\u51b2\u7a81\u65e7\u8bb0\u5fc6\u3002<\/li>\n<\/ul>\n<p><strong>\u8fd0\u884c\u89c2\u6d4b\u80fd\u529b\uff1a<\/strong> \u7cfb\u7edf\u63d0\u4f9b\u8fd0\u884c\u6982\u89c8\u3001\u8bb0\u5fc6\u7c7b\u578b\u5206\u5e03\u3001\u65f6\u95f4\u8d8b\u52bf\u3001Top Agents \u548c Cube \u660e\u7ec6\u7b49\u67e5\u8be2\u80fd\u529b\uff0c\u53ef\u7528\u4e8e\u4e86\u89e3\u8bb0\u5fc6\u6570\u636e\u7684\u89c4\u6a21\u3001\u5206\u7c7b\u3001\u6765\u6e90\u53ca\u53d8\u5316\u8d8b\u52bf\uff0c\u5e76\u652f\u6301\u6309\u65f6\u95f4\u8303\u56f4\u67e5\u770b\u957f\u671f\u8bb0\u5fc6\u641c\u7d22\u8d8b\u52bf\uff0c\u9002\u5408\u65e5\u5e38\u5de1\u68c0\u3001\u6570\u636e\u5206\u5e03\u5206\u6790\u548c\u5f02\u5e38\u5b9a\u4f4d\u3002<\/p>\n<h2>\u516b\u3001\u603b\u7ed3\u4e0e\u540e\u7eed\u5de5\u4f5c<\/h2>\n<p>\u77ed\u671f\u8bb0\u5fc6\u8d1f\u8d23\u628a\u5f53\u524d\u4f1a\u8bdd\u5e26\u5165\u4e0b\u4e00\u8f6e\uff0c\u957f\u671f\u8bb0\u5fc6\u8d1f\u8d23\u628a\u7ecf\u8fc7\u7b5b\u9009\u7684\u7528\u6237\u4e8b\u5b9e\u548c Agent \u7ecf\u9a8c\u5e26\u5230\u540e\u7eed\u4f1a\u8bdd\u3002\u4e24\u6761\u94fe\u8def\u5728\u8bf7\u6c42\u524d\u5e76\u884c\u8bfb\u53d6\uff0c\u5728\u4f1a\u8bdd\u7ed3\u675f\u540e\u901a\u8fc7\u5f02\u6b65\u4efb\u52a1\u8854\u63a5\uff1b\u957f\u671f\u8bb0\u5fc6\u518d\u6309 scope \u548c Token Budget \u63a7\u5236\u6ce8\u5165\u5185\u5bb9\u3002<\/p>\n<p>\u5f53\u524d\u65b9\u6848\u5df2\u8986\u76d6 Redis\/MySQL \u56de\u9000\u3001MemOS \u8bed\u4e49\u68c0\u7d22\u3001LLM \u5224\u65ad\u3001\u672c\u5730\u53bb\u91cd\u3001\u51b2\u7a81\u5904\u7406\u548c\u5148\u5199\u540e\u5220\u3002\u4ecd\u9700\u8865\u9f50\u751f\u4ea7\u6d41\u91cf\u4e0b\u7684\u5ef6\u8fdf\u4e0e\u5931\u8d25\u7387\u89c2\u6d4b\uff0c\u4ee5\u53ca\u5916\u90e8\u8bb0\u5fc6\u670d\u52a1\u5931\u8d25\u540e\u7684\u8865\u507f\u673a\u5236\u3002<\/p>\n<h2>\u5f80\u671f\u56de\u987e<\/h2>\n<p>1.<a href=\"https:\/\/segmentfault.com\/a\/1190000048182092\" target=\"_blank\" rel=\"noopener noreferrer\">EP-Harness\uff1a\u4ece\u4e2a\u4eba AI Coding \u5230\u56e2\u961f\u7ea7 Agent \u5de5\u4f5c\u6d41\uff5c\u5f97\u7269\u6280\u672f<\/a><\/p>\n<p>2.<a href=\"https:\/\/segmentfault.com\/a\/1190000048154229\" target=\"_blank\" rel=\"noopener noreferrer\">\u5f97\u7269\u77e5\u8bc6\u95ee\u7b54\uff1a\u590d\u5408\u68c0\u7d22 Agent \u7684\u7cfb\u7edf\u8bbe\u8ba1\u5b9e\u8df5<\/a><\/p>\n<p>3.<a href=\"https:\/\/segmentfault.com\/a\/1190000048124022\" target=\"_blank\" rel=\"noopener noreferrer\">\u5b9e\u6218\u4ece\u96f6\u5f00\u59cb\u6784\u5efa\u4e00\u4e2aCoding Agent\uff1aViolin \uff5c\u5f97\u7269\u6280\u672f<\/a><\/p>\n<p>4.<a href=\"https:\/\/segmentfault.com\/a\/1190000048094670\" target=\"_blank\" rel=\"noopener noreferrer\">AI Native \u4ea4\u6613\u6838\u5fc3\u7cfb\u7edf\u7684\u7814\u53d1\u8303\u5f0f\uff5c\u5f97\u7269\u6280\u672f<\/a><\/p>\n<p>5.<a href=\"\" target=\"_blank\" rel=\"noopener noreferrer\">\u63a8\u8350\u7cfb\u7edf\u4f53\u9a8c\u7684\u6570\u5b57\u5316\u7a81\u7834\uff1a\u5f97\u7269\u81ea\u52a8\u5316\u8bc4\u6d4b\u5e73\u53f0\u7684\u6280\u672f\u5b9e\u8df5\uff5cAICon \u6587\u7ae0\u6574\u7406<\/a><\/p>\n<h2>\u6587 \/ \u5076\u5566<\/h2>\n<p>\u5173\u6ce8\u5f97\u7269\u6280\u672f\uff0c\u6bcf\u5468\u56db\u66f4\u65b0\u6280\u672f\u5e72\u8d27<\/p>\n<p>\u8981\u662f\u89c9\u5f97\u6587\u7ae0\u5bf9\u4f60\u6709\u5e2e\u52a9\u7684\u8bdd\uff0c\u6b22\u8fce\u8bc4\u8bba\u8f6c\u53d1\u70b9\u8d5e\uff5e<\/p>\n<p>\u672a\u7ecf\u5f97\u7269\u6280\u672f\u8bb8\u53ef\u4e25\u7981\u8f6c\u8f7d\uff0c\u5426\u5219\u4f9d\u6cd5\u8ffd\u7a76\u6cd5\u5f8b\u8d23\u4efb\u3002<\/p>\n<p><a href=\"https:\/\/segmentfault.com\/a\/1190000048215513\">https:\/\/segmentfault.com\/a\/1190000048215513<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4e00\u3001\u80cc\u666f\u53ca\u6574\u4f53\u67b6\u6784\u6982\u89c8 \u5728 MultiAgent \u5e73\u53f0\u4e2d\uff0cAgent \u4e00\u6b21\u8bf7\u6c42\u53ef\u80fd\u540c\u65f6\u7ecf\u8fc7\u6a21\u578b\u3001MCP\/A2A [&hellip;]<\/p>\n","protected":false},"author":8,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-10021437","post","type-post","status-publish","format-standard","hentry","category-share"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10021437","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10021437"}],"version-history":[{"count":0,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10021437\/revisions"}],"wp:attachment":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10021437"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10021437"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10021437"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}