Commit bd287386 authored by Wade's avatar Wade

summary ok

parent afaa731b
{"level":"info","pid":48106,"time":1749131682,"caller":"/Users/wade/project/wuban/agentchat/log.go:69","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":48106,"method":"DeepSeek.Init","time":1749131682,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":48106,"method":"DeepSeek.Init","time":1749131682,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":48106,"method":"Milvus.Init","time":1749131682,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":48106,"method":"Milvus.Init","time":1749131683,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":48106,"method":"GraphKnowledge.Init","time":1749131683,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":48106,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749131683,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":48106,"method":"GraphKnowledge.Init","time":1749131683,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":48106,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749131683,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":48106,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749131683,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":48106,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749131684,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":48106,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749131684,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":48106,"method":"DefineIndexerAndRetriever","time":1749131684,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":48106,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749131684,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":48106,"method":"GraphKnowledge.newDocStore","time":1749131684,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":48106,"method":"DefineIndexerAndRetriever","time":1749131684,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":48106,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749131685,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":48106,"method":"KnowledgeClient.Init","time":1749131685,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"error","pid":48106,"method":"KnowledgeClient.Init","time":1749131685,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:79","message":"SecretID and SecretKey are required"}
{"level":"fatal","pid":48106,"time":1749131685,"caller":"/Users/wade/project/wuban/agentchat/main.go:261","message":"Failed to initialize KnowledgeClient: knowledge: SecretID and SecretKey are required"}
{"level":"info","pid":48510,"time":1749131759,"caller":"/Users/wade/project/wuban/agentchat/log.go:69","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":48510,"method":"DeepSeek.Init","time":1749131759,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":48510,"method":"DeepSeek.Init","time":1749131759,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":48510,"method":"Milvus.Init","time":1749131759,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":48510,"method":"Milvus.Init","time":1749131760,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":48510,"method":"GraphKnowledge.Init","time":1749131760,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":48510,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749131760,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":48510,"method":"GraphKnowledge.Init","time":1749131760,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":48510,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749131760,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":48510,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749131760,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":48510,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749131761,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":48510,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749131761,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":48510,"method":"DefineIndexerAndRetriever","time":1749131761,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":48510,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749131761,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":48510,"method":"GraphKnowledge.newDocStore","time":1749131761,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":48510,"method":"DefineIndexerAndRetriever","time":1749131761,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":48510,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749131763,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":48510,"method":"KnowledgeClient.Init","time":1749131763,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":48510,"method":"KnowledgeClient.Init","time":1749131763,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":48510,"time":1749131763,"caller":"/Users/wade/project/wuban/agentchat/main.go:267","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":48510,"time":1749131772,"caller":"/Users/wade/project/wuban/agentchat/main.go:281","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":48510,"time":1749131772,"caller":"/Users/wade/project/wuban/agentchat/main.go:307","message":"qaAsJson--------{\"ID\":35,\"CreatedAt\":\"2025-06-05T10:48:41.391675Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":48510,"method":"docStore.Retrieve","collection":"chatRag1","time":1749131772,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":48510,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749131774,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":48510,"time":1749131774,"caller":"/Users/wade/project/wuban/agentchat/main.go:333","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":48510,"method":"docStore.Retrieve","space_id":"","time":1749131774,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":48510,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749131782,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":48510,"time":1749131782,"caller":"/Users/wade/project/wuban/agentchat/main.go:349","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":48980,"time":1749131845,"caller":"/Users/wade/project/wuban/agentchat/log.go:69","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":48980,"method":"DeepSeek.Init","time":1749131845,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":48980,"method":"DeepSeek.Init","time":1749131845,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":48980,"method":"Milvus.Init","time":1749131845,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":48980,"method":"Milvus.Init","time":1749131846,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":48980,"method":"GraphKnowledge.Init","time":1749131846,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":48980,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749131846,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":48980,"method":"GraphKnowledge.Init","time":1749131846,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":48980,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749131846,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":48980,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749131846,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":48980,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749131847,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":48980,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749131847,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":48980,"method":"DefineIndexerAndRetriever","time":1749131847,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":48980,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749131847,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":48980,"method":"GraphKnowledge.newDocStore","time":1749131847,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":48980,"method":"DefineIndexerAndRetriever","time":1749131847,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":48980,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749131848,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":48980,"method":"KnowledgeClient.Init","time":1749131848,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":48980,"method":"KnowledgeClient.Init","time":1749131848,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":48980,"time":1749131848,"caller":"/Users/wade/project/wuban/agentchat/main.go:267","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":48980,"time":1749131855,"caller":"/Users/wade/project/wuban/agentchat/main.go:281","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":48980,"time":1749131855,"caller":"/Users/wade/project/wuban/agentchat/main.go:307","message":"qaAsJson--------{\"ID\":36,\"CreatedAt\":\"2025-06-05T13:56:12.838893Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":48980,"method":"docStore.Retrieve","collection":"chatRag1","time":1749131855,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":48980,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749131858,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":48980,"time":1749131858,"caller":"/Users/wade/project/wuban/agentchat/main.go:333","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":48980,"method":"docStore.Retrieve","space_id":"","time":1749131858,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":48980,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749131868,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":48980,"time":1749131868,"caller":"/Users/wade/project/wuban/agentchat/main.go:349","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":49330,"time":1749131919,"caller":"/Users/wade/project/wuban/agentchat/log.go:68","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":49330,"method":"DeepSeek.Init","time":1749131919,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":49330,"method":"DeepSeek.Init","time":1749131919,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":49330,"method":"Milvus.Init","time":1749131919,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":49330,"method":"Milvus.Init","time":1749131920,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":49330,"method":"GraphKnowledge.Init","time":1749131920,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":49330,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749131920,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":49330,"method":"GraphKnowledge.Init","time":1749131920,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":49330,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749131920,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":49330,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749131920,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":49330,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749131921,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":49330,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749131921,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":49330,"method":"DefineIndexerAndRetriever","time":1749131921,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":49330,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749131921,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":49330,"method":"GraphKnowledge.newDocStore","time":1749131921,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":49330,"method":"DefineIndexerAndRetriever","time":1749131921,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":49330,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749131922,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":49330,"method":"KnowledgeClient.Init","time":1749131922,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":49330,"method":"KnowledgeClient.Init","time":1749131922,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":49330,"time":1749131922,"caller":"/Users/wade/project/wuban/agentchat/main.go:263","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":49330,"time":1749131926,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":49330,"time":1749131926,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":37,\"CreatedAt\":\"2025-06-05T13:57:36.176828Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","collection":"chatRag1","time":1749131926,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749131929,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":49330,"time":1749131929,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","space_id":"","time":1749131929,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749131935,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":49330,"time":1749131935,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":49330,"time":1749135401,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":49330,"time":1749135428,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":38,\"CreatedAt\":\"2025-06-05T13:58:47.372064Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","collection":"chatRag1","time":1749135428,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749135433,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":49330,"time":1749135433,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","space_id":"","time":1749135433,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":49330,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749135440,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":49330,"time":1749135440,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":3634,"time":1749179323,"caller":"/Users/wade/project/wuban/agentchat/log.go:68","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":3634,"method":"DeepSeek.Init","time":1749179323,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":3634,"method":"DeepSeek.Init","time":1749179323,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":3634,"method":"Milvus.Init","time":1749179323,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":3634,"method":"Milvus.Init","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":3634,"method":"GraphKnowledge.Init","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":3634,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":3634,"method":"GraphKnowledge.Init","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":3634,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":3634,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":3634,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":3634,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":3634,"method":"DefineIndexerAndRetriever","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":3634,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":3634,"method":"GraphKnowledge.newDocStore","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":3634,"method":"DefineIndexerAndRetriever","time":1749179324,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":3634,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749179325,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":3634,"method":"KnowledgeClient.Init","time":1749179325,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":3634,"method":"KnowledgeClient.Init","time":1749179325,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":3634,"time":1749179325,"caller":"/Users/wade/project/wuban/agentchat/main.go:263","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":3634,"time":1749179345,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":3634,"time":1749179346,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":39,\"CreatedAt\":\"2025-06-05T14:57:08.59507Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":3634,"method":"docStore.Retrieve","collection":"chatRag1","time":1749179346,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"error","pid":3634,"error":"doRequest: error sending request: Post \"https://generativelanguage.googleapis.com//v1beta/models/embedding-001:batchEmbedContents\": dial tcp 74.125.135.95:443: i/o timeout","method":"docStore.Retrieve","collection":"chatRag1","time":1749179376,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:508","message":"Embedding failed"}
{"level":"error","pid":3634,"time":1749179376,"caller":"/Users/wade/project/wuban/agentchat/main.go:320","message":"milvus Retrieve err.Error() milvus retrieve embedding failed: doRequest: error sending request: Post \"https://generativelanguage.googleapis.com//v1beta/models/embedding-001:batchEmbedContents\": dial tcp 74.125.135.95:443: i/o timeout"}
{"level":"info","pid":3634,"method":"docStore.Retrieve","space_id":"","time":1749179376,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":3634,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749179384,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":3634,"time":1749179384,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":3634,"method":"KnowledgeClient.QueryRewriteWithSummary","user_question":"What is the capital of UK?","assistant_answer":"The graph context indicates that the knowledge base does not have the answer to your question. I do not have the information to answer your question about the capital of the UK.\n","history_summary":"","time":1749179395,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:256","message":"Starting query rewrite with summary operation"}
{"level":"info","pid":3634,"method":"KnowledgeClient.QueryRewrite","message_count":2,"model":"lke-query-rewrite-base","time":1749179395,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:131","message":"Starting query rewrite operation"}
{"level":"error","pid":3634,"error":"[TencentCloudSDKError] Code=InvalidParameter, Message=20024-invalid params, RequestId=bca5a1f8-7d20-4313-a59a-66f8e25c2825","method":"KnowledgeClient.QueryRewrite","time":1749179400,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:206","message":"Tencent Cloud API error"}
{"level":"error","pid":3634,"time":1749179400,"caller":"/Users/wade/project/wuban/agentchat/main.go:364","message":"tencent cloud api error: [TencentCloudSDKError] Code=InvalidParameter, Message=20024-invalid params, RequestId=bca5a1f8-7d20-4313-a59a-66f8e25c2825"}
{"level":"info","pid":3634,"question":"What is the capital of UK?","context":"","graph":"知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n","last summary":"","answer":"The graph context indicates that the knowledge base does not have the answer to your question. I do not have the information to answer your question about the capital of the UK.\n","time":1749179400,"caller":"/Users/wade/project/wuban/agentchat/main.go:380","message":"Question and answer pair recorded"}
{"level":"info","pid":3634,"time":1749179415,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":3634,"time":1749179415,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":40,\"CreatedAt\":\"2025-06-06T03:09:06.196118Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":3634,"method":"docStore.Retrieve","collection":"chatRag1","time":1749179415,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":3634,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749179417,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":3634,"time":1749179417,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":3634,"method":"docStore.Retrieve","space_id":"","time":1749179417,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":3634,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749179422,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":3634,"time":1749179422,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":3634,"method":"KnowledgeClient.QueryRewriteWithSummary","user_question":"What is the capital of UK?","assistant_answer":"The provided context doesn't contain the answer to your question. The capital of the UK is London.\n","history_summary":"","time":1749179423,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:256","message":"Starting query rewrite with summary operation"}
{"level":"info","pid":3634,"method":"KnowledgeClient.QueryRewrite","message_count":2,"model":"lke-query-rewrite-base","time":1749179423,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:131","message":"Starting query rewrite operation"}
{"level":"error","pid":3634,"error":"[TencentCloudSDKError] Code=InvalidParameter, Message=20024-invalid params, RequestId=5063326c-2f74-4f7d-9890-771587cde628","method":"KnowledgeClient.QueryRewrite","time":1749179423,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:206","message":"Tencent Cloud API error"}
{"level":"error","pid":3634,"time":1749179423,"caller":"/Users/wade/project/wuban/agentchat/main.go:364","message":"tencent cloud api error: [TencentCloudSDKError] Code=InvalidParameter, Message=20024-invalid params, RequestId=5063326c-2f74-4f7d-9890-771587cde628"}
{"level":"info","pid":3634,"question":"What is the capital of UK?","context":"Paris is the capital of France?\nUSA is the largest importer of coffee?\n","graph":"知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n","last summary":"","answer":"The provided context doesn't contain the answer to your question. The capital of the UK is London.\n","time":1749179423,"caller":"/Users/wade/project/wuban/agentchat/main.go:380","message":"Question and answer pair recorded"}
{"level":"info","pid":4733,"time":1749180547,"caller":"/Users/wade/project/wuban/agentchat/log.go:68","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":4733,"method":"DeepSeek.Init","time":1749180547,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":4733,"method":"DeepSeek.Init","time":1749180547,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":4733,"method":"Milvus.Init","time":1749180547,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":4733,"method":"Milvus.Init","time":1749180548,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":4733,"method":"GraphKnowledge.Init","time":1749180548,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":4733,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749180548,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":4733,"method":"GraphKnowledge.Init","time":1749180548,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":4733,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749180548,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":4733,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749180548,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":4733,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749180549,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":4733,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749180549,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":4733,"method":"DefineIndexerAndRetriever","time":1749180549,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":4733,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749180549,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":4733,"method":"GraphKnowledge.newDocStore","time":1749180549,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":4733,"method":"DefineIndexerAndRetriever","time":1749180549,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":4733,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749180550,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":4733,"method":"KnowledgeClient.Init","time":1749180550,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":4733,"method":"KnowledgeClient.Init","time":1749180550,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":4733,"time":1749180550,"caller":"/Users/wade/project/wuban/agentchat/main.go:263","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":4733,"time":1749180554,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":4733,"time":1749180554,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":41,\"CreatedAt\":\"2025-06-06T03:10:15.510778Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":4733,"method":"docStore.Retrieve","collection":"chatRag1","time":1749180554,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":4733,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749180556,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":4733,"time":1749180556,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":4733,"method":"docStore.Retrieve","space_id":"","time":1749180556,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":4733,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749180561,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":4733,"time":1749180561,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":4733,"method":"KnowledgeClient.QueryRewriteWithSummary","user_question":"What is the capital of UK?","assistant_answer":"I am sorry, but the provided context does not contain the answer to your question about the capital of the UK.\n","history_summary":"","time":1749180562,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:256","message":"Starting query rewrite with summary operation"}
{"level":"info","pid":4733,"method":"KnowledgeClient.QueryRewrite","message_count":2,"model":"lke-query-rewrite-base","time":1749180562,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:131","message":"Starting query rewrite operation"}
{"level":"error","pid":4733,"error":"[TencentCloudSDKError] Code=InvalidParameter, Message=20024-invalid params, RequestId=51b1a188-a8c9-4956-839a-bc3f83ace3e5","method":"KnowledgeClient.QueryRewrite","time":1749180563,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:206","message":"Tencent Cloud API error"}
{"level":"error","pid":4733,"time":1749180563,"caller":"/Users/wade/project/wuban/agentchat/main.go:367","message":"tencent cloud api error: [TencentCloudSDKError] Code=InvalidParameter, Message=20024-invalid params, RequestId=51b1a188-a8c9-4956-839a-bc3f83ace3e5"}
{"level":"info","pid":4733,"question":"What is the capital of UK?","context":"Paris is the capital of France?\nUSA is the largest importer of coffee?\n","graph":"知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n","last summary":"","answer":"I am sorry, but the provided context does not contain the answer to your question about the capital of the UK.\n","time":1749180563,"caller":"/Users/wade/project/wuban/agentchat/main.go:383","message":"Question and answer pair recorded"}
{"level":"info","pid":6105,"time":1749180845,"caller":"/Users/wade/project/wuban/agentchat/log.go:68","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":6105,"method":"DeepSeek.Init","time":1749180845,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":6105,"method":"DeepSeek.Init","time":1749180845,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":6105,"method":"Milvus.Init","time":1749180845,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":6105,"method":"Milvus.Init","time":1749180846,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":6105,"method":"GraphKnowledge.Init","time":1749180846,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":6105,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749180846,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":6105,"method":"GraphKnowledge.Init","time":1749180846,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":6105,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749180846,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":6105,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749180846,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":6105,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749180848,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":6105,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749180848,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":6105,"method":"DefineIndexerAndRetriever","time":1749180848,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":6105,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749180848,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":6105,"method":"GraphKnowledge.newDocStore","time":1749180848,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":6105,"method":"DefineIndexerAndRetriever","time":1749180848,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":6105,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749180849,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":6105,"method":"KnowledgeClient.Init","time":1749180849,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":6105,"method":"KnowledgeClient.Init","time":1749180849,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":6105,"time":1749180849,"caller":"/Users/wade/project/wuban/agentchat/main.go:263","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":6105,"time":1749180858,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":6105,"time":1749180859,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":42,\"CreatedAt\":\"2025-06-06T03:29:14.509175Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":null,\"Summary\":null,\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":6105,"method":"docStore.Retrieve","collection":"chatRag1","time":1749180859,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":6105,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749180861,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6105,"time":1749180861,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":6105,"method":"docStore.Retrieve","space_id":"","time":1749180861,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":6105,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749180867,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6105,"time":1749180867,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":6105,"method":"KnowledgeClient.QueryRewriteWithSummary","user_question":"What is the capital of UK?","assistant_answer":"The available knowledge base does not contain information about the capital of the UK.\n","history_summary":"The available knowledge base does not contain information about the capital of the UK.\n","time":1749180868,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:256","message":"Starting query rewrite with summary operation"}
{"level":"info","pid":6105,"method":"KnowledgeClient.QueryRewrite","message_count":3,"model":"lke-query-rewrite-base","time":1749180868,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:131","message":"Starting query rewrite operation"}
{"level":"info","pid":6105,"method":"KnowledgeClient.QueryRewrite","rewritten_query":"Conversation summary: The available knowledge base does not contain information about the capital of the UK.","request_id":"15f1ce0c-a83f-4d95-af22-33a3bd829e8d","usage":{"InputTokens":74,"OutputTokens":19,"TotalTokens":93},"raw_response":"{\"Response\":{\"Content\":\"Conversation summary: The available knowledge base does not contain information about the capital of the UK.\",\"Usage\":{\"InputTokens\":74,\"OutputTokens\":19,\"TotalTokens\":93},\"RequestId\":\"15f1ce0c-a83f-4d95-af22-33a3bd829e8d\"}}","time":1749180870,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:237","message":"Query rewrite operation completed successfully"}
{"level":"info","pid":6105,"question":"What is the capital of UK?","context":"Paris is the capital of France?\nUSA is the largest importer of coffee?\n","graph":"知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n","last summary":"The available knowledge base does not contain information about the capital of the UK.\n","answer":"The available knowledge base does not contain information about the capital of the UK.\n","time":1749180870,"caller":"/Users/wade/project/wuban/agentchat/main.go:387","message":"Question and answer pair recorded"}
{"level":"info","pid":6250,"time":1749181044,"caller":"/Users/wade/project/wuban/agentchat/log.go:68","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":6250,"method":"DeepSeek.Init","time":1749181044,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":6250,"method":"DeepSeek.Init","time":1749181044,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":6250,"method":"Milvus.Init","time":1749181044,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":6250,"method":"Milvus.Init","time":1749181045,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":6250,"method":"GraphKnowledge.Init","time":1749181045,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":6250,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749181045,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":6250,"method":"GraphKnowledge.Init","time":1749181045,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":6250,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749181045,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":6250,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749181045,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":6250,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749181046,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":6250,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749181046,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":6250,"method":"DefineIndexerAndRetriever","time":1749181046,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":6250,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749181046,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":6250,"method":"GraphKnowledge.newDocStore","time":1749181046,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":6250,"method":"DefineIndexerAndRetriever","time":1749181046,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":6250,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749181047,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":6250,"method":"KnowledgeClient.Init","time":1749181047,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":6250,"method":"KnowledgeClient.Init","time":1749181047,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":6250,"time":1749181047,"caller":"/Users/wade/project/wuban/agentchat/main.go:263","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":6250,"time":1749181055,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"What is the capital of UK?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":6250,"time":1749181055,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":43,\"CreatedAt\":\"2025-06-06T03:34:19.041174Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":\"The available knowledge base does not contain information about the capital of the UK.\\n\",\"Summary\":\"\",\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","collection":"chatRag1","time":1749181055,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749181058,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6250,"time":1749181058,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","space_id":"","time":1749181058,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749181065,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6250,"time":1749181065,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":6250,"method":"KnowledgeClient.QueryRewriteWithSummary","user_question":"What is the capital of UK?","assistant_answer":"The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\n","history_summary":"The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\n","time":1749181066,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:256","message":"Starting query rewrite with summary operation"}
{"level":"info","pid":6250,"method":"KnowledgeClient.QueryRewrite","message_count":3,"model":"lke-query-rewrite-base","time":1749181066,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:131","message":"Starting query rewrite operation"}
{"level":"info","pid":6250,"method":"KnowledgeClient.QueryRewrite","rewritten_query":"Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","request_id":"e8ef75a3-6f35-4766-8eea-b8a7d3506c84","usage":{"InputTokens":154,"OutputTokens":59,"TotalTokens":213},"raw_response":"{\"Response\":{\"Content\":\"Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\",\"Usage\":{\"InputTokens\":154,\"OutputTokens\":59,\"TotalTokens\":213},\"RequestId\":\"e8ef75a3-6f35-4766-8eea-b8a7d3506c84\"}}","time":1749181069,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:237","message":"Query rewrite operation completed successfully"}
{"level":"info","pid":6250,"question":"What is the capital of UK?","context":"Paris is the capital of France?\nUSA is the largest importer of coffee?\n","graph":"知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n","last summary":"The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\n","answer":"The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\n","time":1749181069,"caller":"/Users/wade/project/wuban/agentchat/main.go:398","message":"Question and answer pair recorded"}
{"level":"info","pid":6250,"time":1749181117,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"你是谁?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":6250,"time":1749181118,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":44,\"CreatedAt\":\"2025-06-06T03:37:35.757771Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"What is the capital of UK?\",\"Answer\":\"The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\\n\",\"Summary\":\"Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\",\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","collection":"chatRag1","time":1749181118,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749181118,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6250,"time":1749181118,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","space_id":"","time":1749181118,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":6250,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749181123,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6250,"time":1749181123,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":6250,"method":"KnowledgeClient.QueryRewriteWithSummary","user_question":"你是谁?","assistant_answer":"我是一个基于Milvus的AI助手。知识库中提供的内容不足以回答你是谁这个问题。\n","history_summary":"Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","time":1749181124,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:256","message":"Starting query rewrite with summary operation"}
{"level":"info","pid":6250,"method":"KnowledgeClient.QueryRewrite","message_count":3,"model":"lke-query-rewrite-base","time":1749181124,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:131","message":"Starting query rewrite operation"}
{"level":"info","pid":6250,"method":"KnowledgeClient.QueryRewrite","rewritten_query":"Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","request_id":"6b4d918c-5e65-4fd8-b1b3-52b961b8170a","usage":{"InputTokens":119,"OutputTokens":62,"TotalTokens":181},"raw_response":"{\"Response\":{\"Content\":\"Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\",\"Usage\":{\"InputTokens\":119,\"OutputTokens\":62,\"TotalTokens\":181},\"RequestId\":\"6b4d918c-5e65-4fd8-b1b3-52b961b8170a\"}}","time":1749181126,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:237","message":"Query rewrite operation completed successfully"}
{"level":"info","pid":6250,"question":"你是谁?","context":"Paris is the capital of France?\nUSA is the largest importer of coffee?\n","graph":"知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n","last summary":"Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","answer":"我是一个基于Milvus的AI助手。知识库中提供的内容不足以回答你是谁这个问题。\n","time":1749181126,"caller":"/Users/wade/project/wuban/agentchat/main.go:398","message":"Question and answer pair recorded"}
{"level":"info","pid":6592,"time":1749181440,"caller":"/Users/wade/project/wuban/agentchat/log.go:68","message":"This message appears when log level set to Debug or Info"}
{"level":"info","pid":6592,"method":"DeepSeek.Init","time":1749181440,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:91","message":"Initializing DeepSeek plugin"}
{"level":"info","pid":6592,"method":"DeepSeek.Init","time":1749181440,"caller":"/Users/wade/project/wuban/agentchat/plugins/deepseek/deepseek.go:104","message":"Initialization successful"}
{"level":"info","pid":6592,"method":"Milvus.Init","time":1749181440,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:75","message":"Initializing Milvus plugin"}
{"level":"info","pid":6592,"method":"Milvus.Init","time":1749181441,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:87","message":"Initialization successful"}
{"level":"info","pid":6592,"method":"GraphKnowledge.Init","time":1749181441,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:299","message":"Initializing GraphKnowledge plugin"}
{"level":"info","pid":6592,"method":"NewClient","ip":"54.92.111.204","port":5670,"time":1749181441,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:93","message":"Creating new GraphRAG client"}
{"level":"info","pid":6592,"method":"GraphKnowledge.Init","time":1749181441,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:311","message":"Initialization successful"}
{"level":"info","pid":6592,"method":"DefineIndexerAndRetriever","collection":"chatRag1","dimension":768,"time":1749181441,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:152","message":"Defining indexer and retriever"}
{"level":"info","pid":6592,"method":"Milvus.newDocStore","collection":"chatRag1","dimension":768,"time":1749181441,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:201","message":"Creating new doc store"}
{"level":"info","pid":6592,"method":"Milvus.newDocStore","collection":"chatRag1","time":1749181442,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:302","message":"Doc store created successfully"}
{"level":"info","pid":6592,"method":"DefineIndexerAndRetriever","collection":"chatRag1","time":1749181442,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:182","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":6592,"method":"DefineIndexerAndRetriever","time":1749181442,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:357","message":"Defining indexer and retriever"}
{"level":"info","pid":6592,"method":"GraphKnowledge.newDocStore","space_id":"","model_name":"Qwen/Qwen2.5-Coder-32B-Instruct","time":1749181442,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:393","message":"Creating new doc store"}
{"level":"info","pid":6592,"method":"GraphKnowledge.newDocStore","time":1749181442,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:399","message":"Doc store created successfully"}
{"level":"info","pid":6592,"method":"DefineIndexerAndRetriever","time":1749181442,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:376","message":"Indexer and retriever defined successfully"}
{"level":"info","pid":6592,"method":"NewKnowledgeClient","endpoint":"lkeap.tencentcloudapi.com","region":"ap-guangzhou","secret_id":"","token":"","time":1749181443,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:43","message":"Creating new KnowledgeClient"}
{"level":"info","pid":6592,"method":"KnowledgeClient.Init","time":1749181443,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:51","message":"Initializing KnowledgeClient"}
{"level":"info","pid":6592,"method":"KnowledgeClient.Init","time":1749181443,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:109","message":"Initialization successful"}
{"level":"info","pid":6592,"time":1749181443,"caller":"/Users/wade/project/wuban/agentchat/main.go:263","message":"KnowledgeClient initialized successfully"}
{"level":"info","pid":6592,"time":1749181451,"caller":"/Users/wade/project/wuban/agentchat/main.go:277","message":"input--------{\"content\":\"你是谁?\",\"model\":\"gpt-3.5-turbo\",\"apiKey\":\"sk-1234567890abcdef\",\"from\":\"Alice\",\"from_id\":\"user123\",\"to\":\"Bob\",\"to_id\":\"user456\"}"}
{"level":"info","pid":6592,"time":1749181451,"caller":"/Users/wade/project/wuban/agentchat/main.go:303","message":"qaAsJson--------{\"ID\":45,\"CreatedAt\":\"2025-06-06T03:38:38.177331Z\",\"FromID\":\"user123\",\"From\":\"Alice\",\"Question\":\"你是谁?\",\"Answer\":\"我是一个基于Milvus的AI助手。知识库中提供的内容不足以回答你是谁这个问题。\\n\",\"Summary\":\"Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\",\"To\":\"Bob\",\"ToID\":\"user456\"}"}
{"level":"info","pid":6592,"method":"docStore.Retrieve","collection":"chatRag1","time":1749181451,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:450","message":"Starting retrieve operation"}
{"level":"info","pid":6592,"method":"docStore.Retrieve","collection":"chatRag1","documents":2,"time":1749181454,"caller":"/Users/wade/project/wuban/agentchat/plugins/milvus/milvus.go:640","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6592,"time":1749181454,"caller":"/Users/wade/project/wuban/agentchat/main.go:329","message":"promptInput.Context: Paris is the capital of France?\nUSA is the largest importer of coffee?\n"}
{"level":"info","pid":6592,"method":"docStore.Retrieve","space_id":"","time":1749181454,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:755","message":"Starting retrieve operation"}
{"level":"info","pid":6592,"method":"docStore.Retrieve","space_id":"","documents":1,"time":1749181460,"caller":"/Users/wade/project/wuban/agentchat/plugins/graphrag/graph.go:892","message":"Retrieve operation completed successfully"}
{"level":"info","pid":6592,"time":1749181460,"caller":"/Users/wade/project/wuban/agentchat/main.go:344","message":"promptInput.Graph : 知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n"}
{"level":"info","pid":6592,"from":"Alice","from_id":"user123","to":"Bob","to_id":"user456","promptInput.Query":"你是谁?","resp.Text()":"我是一个基于Milvus的助手,但我能提供的信息有限。目前我只知道巴黎是法国的首都,美国是最大的咖啡进口国。知识库的信息不足以回答“你是谁”这个问题。\n","promptInput.Summary":"Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","time":1749181461,"caller":"/Users/wade/project/wuban/agentchat/main.go:371","message":"QueryRewriteWithSummary"}
{"level":"info","pid":6592,"method":"KnowledgeClient.QueryRewriteWithSummary","user_question":"你是谁?","assistant_answer":"我是一个基于Milvus的助手,但我能提供的信息有限。目前我只知道巴黎是法国的首都,美国是最大的咖啡进口国。知识库的信息不足以回答“你是谁”这个问题。\n","history_summary":"Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","time":1749181461,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:256","message":"Starting query rewrite with summary operation"}
{"level":"info","pid":6592,"method":"KnowledgeClient.QueryRewrite","message_count":3,"model":"lke-query-rewrite-base","time":1749181461,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:131","message":"Starting query rewrite operation"}
{"level":"info","pid":6592,"method":"KnowledgeClient.QueryRewrite","rewritten_query":"Conversation summary: Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","request_id":"01a825ea-5033-4bba-b62b-8597c780167d","usage":{"InputTokens":143,"OutputTokens":65,"TotalTokens":208},"raw_response":"{\"Response\":{\"Content\":\"Conversation summary: Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.\",\"Usage\":{\"InputTokens\":143,\"OutputTokens\":65,\"TotalTokens\":208},\"RequestId\":\"01a825ea-5033-4bba-b62b-8597c780167d\"}}","time":1749181464,"caller":"/Users/wade/project/wuban/agentchat/plugins/knowledge/knowledge.go:237","message":"Query rewrite operation completed successfully"}
{"level":"info","pid":6592,"from":"Alice","from_id":"user123","to":"Bob","to_id":"user456","question":"你是谁?","context":"Paris is the capital of France?\nUSA is the largest importer of coffee?\n","graph":"知识库中提供的内容不足以回答此问题\n\n<references title=\"References\" references=\"[]\" />\n","last summary":"Conversation summary: Conversation summary: The provided context does not contain the answer to your question. The context mentions Paris is the capital of France and the USA is the largest importer of coffee. The graph context also indicates a lack of information. Therefore, I cannot answer your question about the capital of the UK.","answer":"我是一个基于Milvus的助手,但我能提供的信息有限。目前我只知道巴黎是法国的首都,美国是最大的咖啡进口国。知识库的信息不足以回答“你是谁”这个问题。\n","time":1749181464,"caller":"/Users/wade/project/wuban/agentchat/main.go:397","message":"Question and answer pair recorded"}
......@@ -23,7 +23,6 @@ func getPackageName() string {
return pkg
}
func loggingInit() {
// debug := flag.Bool("debug", false, "sets log level to debug")
......
......@@ -6,6 +6,7 @@ import (
"flag"
"fmt"
"net/http"
"os"
"strings"
"time"
......@@ -14,6 +15,7 @@ import (
"github.com/rs/zerolog"
"github.com/wade-liwei/agentchat/plugins/deepseek"
"github.com/wade-liwei/agentchat/plugins/graphrag"
"github.com/wade-liwei/agentchat/plugins/knowledge" // Import knowledge package
"github.com/wade-liwei/agentchat/plugins/milvus"
"github.com/firebase/genkit/go/plugins/evaluators"
......@@ -76,7 +78,6 @@ type simpleQaPromptInput struct {
// Please provide a response that aligns with the given personality while leveraging the provided context, graph, and conversation summary.
// `
const simpleQaPromptTemplate = `
You're a helpful agent that answers the user's questions based on the provided context.
......@@ -94,18 +95,16 @@ Instructions:
- Ensure responses leverage the Previous conversation summary when relevant.
`
func main() {
// Define command-line flags with hardcoded values as defaults
deepseekAPIKey := flag.String("deepseek-api-key", "sk-9f70df871a7c4b8aa566a3c7a0603706", "DeepSeek API key")
milvusAddr := flag.String("milvus-addr", "54.92.111.204:19530", "Milvus server address")
graphragAddr := flag.String("graphrag-addr", "54.92.111.204:5670", "GraphRAG server address")
googleAIApiKey := flag.String("googleai-api-key", "AIzaSyCoYBOmnwRWlH_-nT25lpn8pMg3T18Q0uI", "Google AI API key")
// Define command-line flags with hardcoded values as defaults
deepseekAPIKey := flag.String("deepseek-api-key", "sk-9f70df871a7c4b8aa566a3c7a0603706", "DeepSeek API key")
milvusAddr := flag.String("milvus-addr", "54.92.111.204:19530", "Milvus server address")
graphragAddr := flag.String("graphrag-addr", "54.92.111.204:5670", "GraphRAG server address")
googleAIApiKey := flag.String("googleai-api-key", "AIzaSyCoYBOmnwRWlH_-nT25lpn8pMg3T18Q0uI", "Google AI API key")
pgConnString := flag.String("pg-conn-string", "postgresql://postgres.awcfgdodiuqnlsobcivq:P99IU9NEoDRPsBfb@aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres", "PostgreSQL connection string")
debug := flag.Bool("debug", false, "sets log level to debug")
flag.Parse()
flag.Parse()
loggingInit()
......@@ -113,6 +112,9 @@ func main() {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
ctx := context.Background()
metrics := []evaluators.MetricConfig{
{
......@@ -126,14 +128,14 @@ func main() {
},
}
// Initialize genkit with plugins using flag/env values
g, err := genkit.Init(ctx, genkit.WithPlugins(
&deepseek.DeepSeek{APIKey: *deepseekAPIKey},
&milvus.Milvus{Addr: *milvusAddr},
&graphrag.GraphKnowledge{Addr: *graphragAddr},
&googlegenai.GoogleAI{APIKey: *googleAIApiKey},
&evaluators.GenkitEval{Metrics: metrics},
))
// Initialize genkit with plugins using flag/env values
g, err := genkit.Init(ctx, genkit.WithPlugins(
&deepseek.DeepSeek{APIKey: *deepseekAPIKey},
&milvus.Milvus{Addr: *milvusAddr},
&graphrag.GraphKnowledge{Addr: *graphragAddr},
&googlegenai.GoogleAI{APIKey: *googleAIApiKey},
&evaluators.GenkitEval{Metrics: metrics},
))
if err != nil {
log.Fatal().Msg(err.Error())
......@@ -250,6 +252,16 @@ func main() {
log.Fatal().Msgf("InitQAStore failed: %v", err)
}
// Initialize KnowledgeClient with test parameters
kc := knowledge.NewKnowledgeClient(knowledge.ClientConfig{
Endpoint: "lkeap.tencentcloudapi.com",
Region: "ap-guangzhou",
})
if err := kc.Init(ctx); err != nil {
log.Fatal().Msgf("Failed to initialize KnowledgeClient: %v", err)
}
log.Info().Msg("KnowledgeClient initialized successfully")
// Define a simple flow that generates jokes about a given topic
genkit.DefineFlow(g, "chat", func(ctx context.Context, input *ChatInput) (Response, error) {
......@@ -319,7 +331,6 @@ func main() {
begin := time.Now()
graphResponse, err := ai.Retrieve(ctx, graphRetriever, ai.WithDocs(dRequest))
if err != nil {
log.Error().Msgf("graph Retrieve err.Error() %s", err.Error())
......@@ -333,10 +344,7 @@ func main() {
log.Info().Msgf("promptInput.Graph : %s", promptInput.Graph)
}
fmt.Println("graph time",time.Since(begin).Seconds())
fmt.Println("graph time", time.Since(begin).Seconds())
resp, err := simpleQaPrompt.Execute(ctx, ai.WithInput(promptInput))
......@@ -347,18 +355,46 @@ func main() {
}, nil
}
if lastok {
if promptInput.Summary == ""{
promptInput.Summary = resp.Text()
}
qa.UpdateQAFields(context.Background(), idx, "", resp.Text())
log.Info().
Str("from",input.From).
Str("from_id",input.FromID).
Str("to",input.To).
Str("to_id",input.ToID).
Str("promptInput.Query",promptInput.Query).
Str("resp.Text()",resp.Text()).
Str("promptInput.Summary",promptInput.Summary).Msg("QueryRewriteWithSummary")
res, err := kc.QueryRewriteWithSummary(context.Background(), promptInput.Query, resp.Text(), promptInput.Summary)
if err != nil {
log.Error().Msg(err.Error())
} else {
qa.UpdateQAFields(context.Background(), idx, res.RewrittenQuery, resp.Text())
/*
{"RewrittenQuery":"Conversation summary: The available knowledge base does not contain information about the capital of the UK.","RawResponse":{"Response":{"Content":"Conversation summary: The available knowledge base does not contain information about the capital of the UK.","Usage":{"InputTokens":74,"OutputTokens":19,"TotalTokens":93},"RequestId":"15f1ce0c-a83f-4d95-af22-33a3bd829e8d"}}}
*/
}
} else {
qa.UpdateQAFields(context.Background(), idx, "", resp.Text())
}
log.Info().
Str("question",promptInput.Query).
Str("context",promptInput.Context).
Str("graph",promptInput.Graph).
Str("last summary",promptInput.Summary).
Str("answer", resp.Text()).
Msg("Question and answer pair recorded")
Str("from",input.From).
Str("from_id",input.FromID).
Str("to",input.To).
Str("to_id",input.ToID).
Str("question", promptInput.Query).
Str("context", promptInput.Context).
Str("graph", promptInput.Graph).
Str("last summary", promptInput.Summary).
Str("answer", resp.Text()).
Msg("Question and answer pair recorded")
return Response{
Data: resp.Text(),
......@@ -392,7 +428,6 @@ func main() {
}
}
type Response struct {
Data string `json:"data"`
Code int `json:"code"`
......
......@@ -16,231 +16,210 @@ import (
const provider = "deepseek"
var (
mediaSupportedModels = []string{deepseek.DeepSeekChat, deepseek.DeepSeekCoder, deepseek.DeepSeekReasoner}
roleMapping = map[ai.Role]string{
ai.RoleUser: deepseek.ChatMessageRoleUser,
ai.RoleModel: deepseek.ChatMessageRoleAssistant,
ai.RoleSystem: deepseek.ChatMessageRoleSystem,
ai.RoleTool: deepseek.ChatMessageRoleTool,
}
mediaSupportedModels = []string{deepseek.DeepSeekChat, deepseek.DeepSeekCoder, deepseek.DeepSeekReasoner}
roleMapping = map[ai.Role]string{
ai.RoleUser: deepseek.ChatMessageRoleUser,
ai.RoleModel: deepseek.ChatMessageRoleAssistant,
ai.RoleSystem: deepseek.ChatMessageRoleSystem,
ai.RoleTool: deepseek.ChatMessageRoleTool,
}
)
// DeepSeek holds configuration for the plugin.
type DeepSeek struct {
APIKey string // DeepSeek API key
APIKey string // DeepSeek API key
mu sync.Mutex // Mutex to control access.
initted bool // Whether the plugin has been initialized.
mu sync.Mutex // Mutex to control access.
initted bool // Whether the plugin has been initialized.
}
// Name returns the provider name.
func (d DeepSeek) Name() string {
return provider
return provider
}
// ModelDefinition represents a model with its name and type.
type ModelDefinition struct {
Name string
Type string
Name string
Type string
}
// DefineModel defines a DeepSeek model in Genkit.
func (d *DeepSeek) DefineModel(g *genkit.Genkit, model ModelDefinition, info *ai.ModelInfo) ai.Model {
log.Info().
Str("method", "DeepSeek.DefineModel").
Str("model_name", model.Name).
Msg("Defining DeepSeek model")
d.mu.Lock()
defer d.mu.Unlock()
if !d.initted {
log.Error().Str("method", "DeepSeek.DefineModel").Msg("DeepSeek not initialized")
panic("deepseek.Init not called")
}
// Define model info, supporting multiturn and system role.
mi := ai.ModelInfo{
Label: model.Name,
Supports: &ai.ModelSupports{
Multiturn: true,
SystemRole: true,
Media: false, // DeepSeek API primarily supports text.
Tools: false, // Tools not yet supported in this implementation.
},
Versions: []string{},
}
if info != nil {
mi = *info
}
meta := &ai.ModelInfo{
Label: model.Name,
Supports: mi.Supports,
Versions: []string{},
}
gen := &generator{model: model, apiKey: d.APIKey}
modelDef := genkit.DefineModel(g, provider, model.Name, meta, gen.generate)
log.Info().
Str("method", "DeepSeek.DefineModel").
Str("model_name", model.Name).
Msg("Model defined successfully")
return modelDef
log.Info().
Str("method", "DeepSeek.DefineModel").
Str("model_name", model.Name).
Msg("Defining DeepSeek model")
d.mu.Lock()
defer d.mu.Unlock()
if !d.initted {
log.Error().Str("method", "DeepSeek.DefineModel").Msg("DeepSeek not initialized")
panic("deepseek.Init not called")
}
// Define model info, supporting multiturn and system role.
mi := ai.ModelInfo{
Label: model.Name,
Supports: &ai.ModelSupports{
Multiturn: true,
SystemRole: true,
Media: false, // DeepSeek API primarily supports text.
Tools: false, // Tools not yet supported in this implementation.
},
Versions: []string{},
}
if info != nil {
mi = *info
}
meta := &ai.ModelInfo{
Label: model.Name,
Supports: mi.Supports,
Versions: []string{},
}
gen := &generator{model: model, apiKey: d.APIKey}
modelDef := genkit.DefineModel(g, provider, model.Name, meta, gen.generate)
log.Info().
Str("method", "DeepSeek.DefineModel").
Str("model_name", model.Name).
Msg("Model defined successfully")
return modelDef
}
// Init initializes the DeepSeek plugin.
func (d *DeepSeek) Init(ctx context.Context, g *genkit.Genkit) error {
log.Info().Str("method", "DeepSeek.Init").Msg("Initializing DeepSeek plugin")
d.mu.Lock()
defer d.mu.Unlock()
if d.initted {
log.Error().Str("method", "DeepSeek.Init").Msg("Plugin already initialized")
return fmt.Errorf("deepseek.Init already called")
}
if d == nil || d.APIKey == "" {
log.Error().Str("method", "DeepSeek.Init").Msg("APIKey is required")
return fmt.Errorf("deepseek: need APIKey")
}
d.initted = true
log.Info().Str("method", "DeepSeek.Init").Msg("Initialization successful")
return nil
log.Info().Str("method", "DeepSeek.Init").Msg("Initializing DeepSeek plugin")
d.mu.Lock()
defer d.mu.Unlock()
if d.initted {
log.Error().Str("method", "DeepSeek.Init").Msg("Plugin already initialized")
return fmt.Errorf("deepseek.Init already called")
}
if d == nil || d.APIKey == "" {
log.Error().Str("method", "DeepSeek.Init").Msg("APIKey is required")
return fmt.Errorf("deepseek: need APIKey")
}
d.initted = true
log.Info().Str("method", "DeepSeek.Init").Msg("Initialization successful")
return nil
}
// generator handles model generation.
type generator struct {
model ModelDefinition
apiKey string
model ModelDefinition
apiKey string
}
// generate implements the Genkit model generation interface.
func (g *generator) generate(ctx context.Context, input *ai.ModelRequest, cb func(context.Context, *ai.ModelResponseChunk) error) (*ai.ModelResponse, error) {
log.Info().
Str("method", "generator.generate").
Str("model_name", g.model.Name).
Int("messages", len(input.Messages)).
Msg("Starting model generation")
if len(input.Messages) == 0 {
log.Error().Str("method", "generator.generate").Msg("Prompt or messages required")
return nil, fmt.Errorf("prompt or messages required")
}
// Initialize DeepSeek client.
client := deepseek.NewClient(g.apiKey)
log.Debug().Str("method", "generator.generate").Msg("DeepSeek client initialized")
// Create a chat completion request
request := &deepseek.ChatCompletionRequest{
Model: g.model.Name,
}
for _, msg := range input.Messages {
role, ok := roleMapping[msg.Role]
if !ok {
log.Error().
Str("method", "generator.generate").
Str("role", string(msg.Role)).
Msg("Unsupported role")
return nil, fmt.Errorf("unsupported role: %s", msg.Role)
}
content := concatMessageParts(msg.Content)
request.Messages = append(request.Messages, deepseek.ChatCompletionMessage{
Role: role,
Content: content,
})
log.Debug().
Str("method", "generator.generate").
Str("role", role).
Str("content", content).
Msg("Added message to request")
}
// Send the request and handle the response
response, err := client.CreateChatCompletion(ctx, request)
if err != nil {
log.Error().
Err(err).
Str("method", "generator.generate").
Msg("Failed to create chat completion")
return nil, fmt.Errorf("create chat completion: %w", err)
}
log.Debug().
Str("method", "generator.generate").
Int("choices", len(response.Choices)).
Msg("Received chat completion response")
// Create a final response with the merged chunks
finalResponse := &ai.ModelResponse{
Request: input,
FinishReason: ai.FinishReason("stop"),
Message: &ai.Message{
Role: ai.RoleModel,
},
}
for _, chunk := range response.Choices {
log.Debug().
Str("method", "generator.generate").
Int("index", chunk.Index).
Str("content", chunk.Message.Content).
Msg("Processing response chunk")
p := ai.Part{
Text: chunk.Message.Content,
Kind: ai.PartKind(chunk.Index),
}
finalResponse.Message.Content = append(finalResponse.Message.Content, &p)
}
log.Info().
Str("method", "generator.generate").
Str("model_name", g.model.Name).
Int("content_parts", len(finalResponse.Message.Content)).
Msg("Model generation completed successfully")
return finalResponse, nil
log.Info().
Str("method", "generator.generate").
Str("model_name", g.model.Name).
Int("messages", len(input.Messages)).
Msg("Starting model generation")
if len(input.Messages) == 0 {
log.Error().Str("method", "generator.generate").Msg("Prompt or messages required")
return nil, fmt.Errorf("prompt or messages required")
}
// Initialize DeepSeek client.
client := deepseek.NewClient(g.apiKey)
log.Debug().Str("method", "generator.generate").Msg("DeepSeek client initialized")
// Create a chat completion request
request := &deepseek.ChatCompletionRequest{
Model: g.model.Name,
}
for _, msg := range input.Messages {
role, ok := roleMapping[msg.Role]
if !ok {
log.Error().
Str("method", "generator.generate").
Str("role", string(msg.Role)).
Msg("Unsupported role")
return nil, fmt.Errorf("unsupported role: %s", msg.Role)
}
content := concatMessageParts(msg.Content)
request.Messages = append(request.Messages, deepseek.ChatCompletionMessage{
Role: role,
Content: content,
})
log.Debug().
Str("method", "generator.generate").
Str("role", role).
Str("content", content).
Msg("Added message to request")
}
// Send the request and handle the response
response, err := client.CreateChatCompletion(ctx, request)
if err != nil {
log.Error().
Err(err).
Str("method", "generator.generate").
Msg("Failed to create chat completion")
return nil, fmt.Errorf("create chat completion: %w", err)
}
log.Debug().
Str("method", "generator.generate").
Int("choices", len(response.Choices)).
Msg("Received chat completion response")
// Create a final response with the merged chunks
finalResponse := &ai.ModelResponse{
Request: input,
FinishReason: ai.FinishReason("stop"),
Message: &ai.Message{
Role: ai.RoleModel,
},
}
for _, chunk := range response.Choices {
log.Debug().
Str("method", "generator.generate").
Int("index", chunk.Index).
Str("content", chunk.Message.Content).
Msg("Processing response chunk")
p := ai.Part{
Text: chunk.Message.Content,
Kind: ai.PartKind(chunk.Index),
}
finalResponse.Message.Content = append(finalResponse.Message.Content, &p)
}
log.Info().
Str("method", "generator.generate").
Str("model_name", g.model.Name).
Int("content_parts", len(finalResponse.Message.Content)).
Msg("Model generation completed successfully")
return finalResponse, nil
}
// concatMessageParts concatenates message parts into a single string.
func concatMessageParts(parts []*ai.Part) string {
log.Debug().
Str("method", "concatMessageParts").
Int("parts", len(parts)).
Msg("Concatenating message parts")
var sb strings.Builder
for _, part := range parts {
if part.IsText() {
sb.WriteString(part.Text)
}
// Ignore non-text parts (e.g., media, tools) as DeepSeek API doesn't support them.
}
result := sb.String()
log.Debug().
Str("method", "concatMessageParts").
Str("result", result).
Msg("Concatenation complete")
return result
log.Debug().
Str("method", "concatMessageParts").
Int("parts", len(parts)).
Msg("Concatenating message parts")
var sb strings.Builder
for _, part := range parts {
if part.IsText() {
sb.WriteString(part.Text)
}
// Ignore non-text parts (e.g., media, tools) as DeepSeek API doesn't support them.
}
result := sb.String()
log.Debug().
Str("method", "concatMessageParts").
Str("result", result).
Msg("Concatenation complete")
return result
}
// package deepseek
// import (
......
......@@ -38,236 +38,236 @@ import (
// Client 知识库客户端
type Client struct {
BaseURL string // 基础URL,例如 "http://54.92.111.204:5670"
BaseURL string // 基础URL,例如 "http://54.92.111.204:5670"
}
// SpaceRequest 创建空间的请求结构体
type SpaceRequest struct {
ID int `json:"id"`
Name string `json:"name"`
VectorType string `json:"vector_type"`
DomainType string `json:"domain_type"`
Desc string `json:"desc"`
Owner string `json:"owner"`
SpaceID int `json:"space_id"`
ID int `json:"id"`
Name string `json:"name"`
VectorType string `json:"vector_type"`
DomainType string `json:"domain_type"`
Desc string `json:"desc"`
Owner string `json:"owner"`
SpaceID int `json:"space_id"`
}
// DocumentRequest 添加文档的请求结构体
type DocumentRequest struct {
DocName string `json:"doc_name"`
DocID int `json:"doc_id"`
DocType string `json:"doc_type"`
DocToken string `json:"doc_token"`
Content string `json:"content"`
Source string `json:"source"`
Labels string `json:"labels"`
Questions []string `json:"questions"`
Metadata map[string]interface{} `json:"metadata"`
DocName string `json:"doc_name"`
DocID int `json:"doc_id"`
DocType string `json:"doc_type"`
DocToken string `json:"doc_token"`
Content string `json:"content"`
Source string `json:"source"`
Labels string `json:"labels"`
Questions []string `json:"questions"`
Metadata map[string]interface{} `json:"metadata"`
}
// ChunkParameters 分片参数
type ChunkParameters struct {
ChunkStrategy string `json:"chunk_strategy"`
TextSplitter string `json:"text_splitter"`
SplitterType string `json:"splitter_type"`
ChunkSize int `json:"chunk_size"`
ChunkOverlap int `json:"chunk_overlap"`
Separator string `json:"separator"`
EnableMerge bool `json:"enable_merge"`
ChunkStrategy string `json:"chunk_strategy"`
TextSplitter string `json:"text_splitter"`
SplitterType string `json:"splitter_type"`
ChunkSize int `json:"chunk_size"`
ChunkOverlap int `json:"chunk_overlap"`
Separator string `json:"separator"`
EnableMerge bool `json:"enable_merge"`
}
// SyncBatchRequest 同步批量处理的请求结构体
type SyncBatchRequest struct {
DocID int `json:"doc_id"`
SpaceID string `json:"space_id"`
ModelName string `json:"model_name"`
ChunkParameters ChunkParameters `json:"chunk_parameters"`
DocID int `json:"doc_id"`
SpaceID string `json:"space_id"`
ModelName string `json:"model_name"`
ChunkParameters ChunkParameters `json:"chunk_parameters"`
}
// NewClient 创建新的客户端实例
func NewClient(ip string, port int) *Client {
log.Info().
Str("method", "NewClient").
Str("ip", ip).
Int("port", port).
Msg("Creating new GraphRAG client")
return &Client{
BaseURL: fmt.Sprintf("http://%s:%d", ip, port),
}
log.Info().
Str("method", "NewClient").
Str("ip", ip).
Int("port", port).
Msg("Creating new GraphRAG client")
return &Client{
BaseURL: fmt.Sprintf("http://%s:%d", ip, port),
}
}
// AddSpace 创建知识空间
func (c *Client) AddSpace(req SpaceRequest) (*http.Response, error) {
log.Info().
Str("method", "Client.AddSpace").
Str("name", req.Name).
Str("owner", req.Owner).
Msg("Adding knowledge space")
url := fmt.Sprintf("%s/knowledge/space/add", c.BaseURL)
body, err := json.Marshal(req)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddSpace").Msg("Failed to marshal request")
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.AddSpace").Msg("Failed to create request")
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddSpace").Msg("Failed to send request")
return nil, fmt.Errorf("failed to send request: %w", err)
}
log.Info().
Str("method", "Client.AddSpace").
Int("status_code", resp.StatusCode).
Msg("Space addition request completed")
return resp, nil
log.Info().
Str("method", "Client.AddSpace").
Str("name", req.Name).
Str("owner", req.Owner).
Msg("Adding knowledge space")
url := fmt.Sprintf("%s/knowledge/space/add", c.BaseURL)
body, err := json.Marshal(req)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddSpace").Msg("Failed to marshal request")
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.AddSpace").Msg("Failed to create request")
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddSpace").Msg("Failed to send request")
return nil, fmt.Errorf("failed to send request: %w", err)
}
log.Info().
Str("method", "Client.AddSpace").
Int("status_code", resp.StatusCode).
Msg("Space addition request completed")
return resp, nil
}
// AddDocument 添加文档
func (c *Client) AddDocument(spaceID string, req DocumentRequest) (*http.Response, error) {
log.Info().
Str("method", "Client.AddDocument").
Str("space_id", spaceID).
Str("doc_name", req.DocName).
Msg("Adding document")
url := fmt.Sprintf("%s/knowledge/%s/document/add", c.BaseURL, spaceID)
body, err := json.Marshal(req)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddDocument").Msg("Failed to marshal request")
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.AddDocument").Msg("Failed to create request")
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddDocument").Msg("Failed to send request")
return nil, fmt.Errorf("failed to send request: %w", err)
}
log.Info().
Str("method", "Client.AddDocument").
Str("space_id", spaceID).
Int("status_code", resp.StatusCode).
Msg("Document addition request completed")
return resp, nil
log.Info().
Str("method", "Client.AddDocument").
Str("space_id", spaceID).
Str("doc_name", req.DocName).
Msg("Adding document")
url := fmt.Sprintf("%s/knowledge/%s/document/add", c.BaseURL, spaceID)
body, err := json.Marshal(req)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddDocument").Msg("Failed to marshal request")
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.AddDocument").Msg("Failed to create request")
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.AddDocument").Msg("Failed to send request")
return nil, fmt.Errorf("failed to send request: %w", err)
}
log.Info().
Str("method", "Client.AddDocument").
Str("space_id", spaceID).
Int("status_code", resp.StatusCode).
Msg("Document addition request completed")
return resp, nil
}
// SyncDocumentsRequest defines the request body for the sync documents endpoint.
type SyncDocumentsRequest struct {
DocIDs []string `json:"doc_ids"`
DocIDs []string `json:"doc_ids"`
}
// SyncDocuments sends a POST request to sync documents for the given spaceID.
func (c *Client) SyncDocuments(spaceID string, docIDs []string) (success bool, err error) {
log.Info().
Str("method", "Client.SyncDocuments").
Str("space_id", spaceID).
Strs("doc_ids", docIDs).
Msg("Syncing documents")
url := fmt.Sprintf("%s/knowledge/%s/document/sync", c.BaseURL, spaceID)
reqBody := SyncDocumentsRequest{
DocIDs: docIDs,
}
body, err := json.Marshal(reqBody)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to marshal request")
return false, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to create request")
return false, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to send request")
return false, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to read response body")
return false, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
log.Error().
Str("method", "Client.SyncDocuments").
Int("status_code", resp.StatusCode).
Str("response_body", string(respBody)).
Msg("Sync request failed")
return false, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(respBody))
}
log.Info().
Str("method", "Client.SyncDocuments").
Str("space_id", spaceID).
Msg("Documents synced successfully")
return true, nil
log.Info().
Str("method", "Client.SyncDocuments").
Str("space_id", spaceID).
Strs("doc_ids", docIDs).
Msg("Syncing documents")
url := fmt.Sprintf("%s/knowledge/%s/document/sync", c.BaseURL, spaceID)
reqBody := SyncDocumentsRequest{
DocIDs: docIDs,
}
body, err := json.Marshal(reqBody)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to marshal request")
return false, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to create request")
return false, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to send request")
return false, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncDocuments").Msg("Failed to read response body")
return false, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
log.Error().
Str("method", "Client.SyncDocuments").
Int("status_code", resp.StatusCode).
Str("response_body", string(respBody)).
Msg("Sync request failed")
return false, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(respBody))
}
log.Info().
Str("method", "Client.SyncDocuments").
Str("space_id", spaceID).
Msg("Documents synced successfully")
return true, nil
}
// SyncBatchDocument 同步批量处理文档
func (c *Client) SyncBatchDocument(spaceID string, req []SyncBatchRequest) (*http.Response, error) {
log.Info().
Str("method", "Client.SyncBatchDocument").
Str("space_id", spaceID).
Int("requests", len(req)).
Msg("Syncing batch documents")
url := fmt.Sprintf("%s/knowledge/%s/document/sync_batch", c.BaseURL, spaceID)
body, err := json.Marshal(req)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncBatchDocument").Msg("Failed to marshal request")
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncBatchDocument").Msg("Failed to create request")
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncBatchDocument").Msg("Failed to send request")
return nil, fmt.Errorf("failed to send request: %w", err)
}
log.Info().
Str("method", "Client.SyncBatchDocument").
Str("space_id", spaceID).
Int("status_code", resp.StatusCode).
Msg("Batch document sync request completed")
return resp, nil
log.Info().
Str("method", "Client.SyncBatchDocument").
Str("space_id", spaceID).
Int("requests", len(req)).
Msg("Syncing batch documents")
url := fmt.Sprintf("%s/knowledge/%s/document/sync_batch", c.BaseURL, spaceID)
body, err := json.Marshal(req)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncBatchDocument").Msg("Failed to marshal request")
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncBatchDocument").Msg("Failed to create request")
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "Client.SyncBatchDocument").Msg("Failed to send request")
return nil, fmt.Errorf("failed to send request: %w", err)
}
log.Info().
Str("method", "Client.SyncBatchDocument").
Str("space_id", spaceID).
Int("status_code", resp.StatusCode).
Msg("Batch document sync request completed")
return resp, nil
}
// The provider used in the registry.
......@@ -275,644 +275,626 @@ const provider = "graphrag"
// Field names for schema.
const (
idField = "id"
textField = "text"
metadataField = "metadata"
idField = "id"
textField = "text"
metadataField = "metadata"
)
// GraphKnowledge holds configuration for the plugin.
type GraphKnowledge struct {
Addr string // Knowledge server address (host:port, e.g., "54.92.111.204:5670").
Addr string // Knowledge server address (host:port, e.g., "54.92.111.204:5670").
client *Client // Knowledge client.
mu sync.Mutex // Mutex to control access.
initted bool // Whether the plugin has been initialized.
client *Client // Knowledge client.
mu sync.Mutex // Mutex to control access.
initted bool // Whether the plugin has been initialized.
}
// Name returns the plugin name.
func (k *GraphKnowledge) Name() string {
return provider
return provider
}
// Init initializes the GraphKnowledge plugin.
func (k *GraphKnowledge) Init(ctx context.Context, g *genkit.Genkit) (err error) {
log.Info().Str("method", "GraphKnowledge.Init").Msg("Initializing GraphKnowledge plugin")
if k == nil {
k = &GraphKnowledge{}
}
k.mu.Lock()
defer k.mu.Unlock()
defer func() {
if err != nil {
log.Error().Err(err).Str("method", "GraphKnowledge.Init").Msg("Initialization failed")
err = fmt.Errorf("graphrag.Init: %w", err)
} else {
log.Info().Str("method", "GraphKnowledge.Init").Msg("Initialization successful")
}
}()
if k.initted {
return errors.New("plugin already initialized")
}
// Load configuration.
addr := k.Addr
if addr == "" {
addr = "54.92.111.204:5670" // Default address.
}
// Initialize Knowledge client.
host, port := parseAddr(addr)
client := NewClient(host, port)
k.client = client
k.initted = true
return nil
log.Info().Str("method", "GraphKnowledge.Init").Msg("Initializing GraphKnowledge plugin")
if k == nil {
k = &GraphKnowledge{}
}
k.mu.Lock()
defer k.mu.Unlock()
defer func() {
if err != nil {
log.Error().Err(err).Str("method", "GraphKnowledge.Init").Msg("Initialization failed")
err = fmt.Errorf("graphrag.Init: %w", err)
} else {
log.Info().Str("method", "GraphKnowledge.Init").Msg("Initialization successful")
}
}()
if k.initted {
return errors.New("plugin already initialized")
}
// Load configuration.
addr := k.Addr
if addr == "" {
addr = "54.92.111.204:5670" // Default address.
}
// Initialize Knowledge client.
host, port := parseAddr(addr)
client := NewClient(host, port)
k.client = client
k.initted = true
return nil
}
// parseAddr splits host:port into host and port.
func parseAddr(addr string) (string, int) {
parts := strings.Split(addr, ":")
if len(parts) != 2 {
log.Warn().
Str("method", "parseAddr").
Str("addr", addr).
Msg("Invalid address format, using default")
return "54.92.111.204", 5670
}
port, err := strconv.Atoi(parts[1])
if err != nil {
log.Error().
Err(err).
Str("method", "parseAddr").
Str("port", parts[1]).
Msg("Failed to parse port, using default")
return "54.92.111.204", 5670
}
return parts[0], port
parts := strings.Split(addr, ":")
if len(parts) != 2 {
log.Warn().
Str("method", "parseAddr").
Str("addr", addr).
Msg("Invalid address format, using default")
return "54.92.111.204", 5670
}
port, err := strconv.Atoi(parts[1])
if err != nil {
log.Error().
Err(err).
Str("method", "parseAddr").
Str("port", parts[1]).
Msg("Failed to parse port, using default")
return "54.92.111.204", 5670
}
return parts[0], port
}
// DefineIndexerAndRetriever defines an Indexer and Retriever for a Knowledge space.
func DefineIndexerAndRetriever(ctx context.Context, g *genkit.Genkit) (ai.Indexer, ai.Retriever, error) {
log.Info().Str("method", "DefineIndexerAndRetriever").Msg("Defining indexer and retriever")
spaceID := ""
modelName := "Qwen/Qwen2.5-Coder-32B-Instruct"
k := genkit.LookupPlugin(g, provider)
if k == nil {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("GraphRAG plugin not found")
return nil, nil, errors.New("graphrag plugin not found; did you call genkit.Init with the graphrag plugin?")
}
knowledge := k.(*GraphKnowledge)
ds, err := knowledge.newDocStore(ctx, spaceID, modelName)
if err != nil {
log.Error().Err(err).Str("method", "DefineIndexerAndRetriever").Msg("Failed to create doc store")
return nil, nil, err
}
indexer := genkit.DefineIndexer(g, provider, spaceID, ds.Index)
retriever := genkit.DefineRetriever(g, provider, spaceID, ds.Retrieve)
log.Info().Str("method", "DefineIndexerAndRetriever").Msg("Indexer and retriever defined successfully")
return indexer, retriever, nil
log.Info().Str("method", "DefineIndexerAndRetriever").Msg("Defining indexer and retriever")
spaceID := ""
modelName := "Qwen/Qwen2.5-Coder-32B-Instruct"
k := genkit.LookupPlugin(g, provider)
if k == nil {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("GraphRAG plugin not found")
return nil, nil, errors.New("graphrag plugin not found; did you call genkit.Init with the graphrag plugin?")
}
knowledge := k.(*GraphKnowledge)
ds, err := knowledge.newDocStore(ctx, spaceID, modelName)
if err != nil {
log.Error().Err(err).Str("method", "DefineIndexerAndRetriever").Msg("Failed to create doc store")
return nil, nil, err
}
indexer := genkit.DefineIndexer(g, provider, spaceID, ds.Index)
retriever := genkit.DefineRetriever(g, provider, spaceID, ds.Retrieve)
log.Info().Str("method", "DefineIndexerAndRetriever").Msg("Indexer and retriever defined successfully")
return indexer, retriever, nil
}
// docStore defines an Indexer and a Retriever.
type docStore struct {
client *Client
spaceID string
modelName string
client *Client
spaceID string
modelName string
}
// newDocStore creates a docStore.
func (k *GraphKnowledge) newDocStore(ctx context.Context, spaceID, modelName string) (*docStore, error) {
log.Info().
Str("method", "GraphKnowledge.newDocStore").
Str("space_id", spaceID).
Str("model_name", modelName).
Msg("Creating new doc store")
if k.client == nil {
log.Error().Str("method", "GraphKnowledge.newDocStore").Msg("GraphRAG client not initialized")
return nil, errors.New("graphrag.Init not called")
}
log.Info().Str("method", "GraphKnowledge.newDocStore").Msg("Doc store created successfully")
return &docStore{
client: k.client,
spaceID: spaceID,
modelName: modelName,
}, nil
log.Info().
Str("method", "GraphKnowledge.newDocStore").
Str("space_id", spaceID).
Str("model_name", modelName).
Msg("Creating new doc store")
if k.client == nil {
log.Error().Str("method", "GraphKnowledge.newDocStore").Msg("GraphRAG client not initialized")
return nil, errors.New("graphrag.Init not called")
}
log.Info().Str("method", "GraphKnowledge.newDocStore").Msg("Doc store created successfully")
return &docStore{
client: k.client,
spaceID: spaceID,
modelName: modelName,
}, nil
}
// Indexer returns the indexer for a space.
func Indexer(g *genkit.Genkit, spaceID string) ai.Indexer {
log.Info().
Str("method", "Indexer").
Str("space_id", spaceID).
Msg("Looking up indexer")
indexer := genkit.LookupIndexer(g, provider, spaceID)
if indexer == nil {
log.Warn().
Str("method", "Indexer").
Str("space_id", spaceID).
Msg("Indexer not found")
}
return indexer
log.Info().
Str("method", "Indexer").
Str("space_id", spaceID).
Msg("Looking up indexer")
indexer := genkit.LookupIndexer(g, provider, spaceID)
if indexer == nil {
log.Warn().
Str("method", "Indexer").
Str("space_id", spaceID).
Msg("Indexer not found")
}
return indexer
}
// Retriever returns the retriever for a space.
func Retriever(g *genkit.Genkit, spaceID string) ai.Retriever {
log.Info().
Str("method", "Retriever").
Str("space_id", spaceID).
Msg("Looking up retriever")
retriever := genkit.LookupRetriever(g, provider, spaceID)
if retriever == nil {
log.Warn().
Str("method", "Retriever").
Str("space_id", spaceID).
Msg("Retriever not found")
}
return retriever
log.Info().
Str("method", "Retriever").
Str("space_id", spaceID).
Msg("Looking up retriever")
retriever := genkit.LookupRetriever(g, provider, spaceID)
if retriever == nil {
log.Warn().
Str("method", "Retriever").
Str("space_id", spaceID).
Msg("Retriever not found")
}
return retriever
}
// generateRandomDocName generates a random alphanumeric string of the specified length.
func GenerateRandomDocName(length int) (string, error) {
log.Debug().
Str("method", "GenerateRandomDocName").
Int("length", length).
Msg("Generating random document name")
const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
var result strings.Builder
result.Grow(length)
for i := 0; i < length; i++ {
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
log.Error().
Err(err).
Str("method", "GenerateRandomDocName").
Msg("Failed to generate random index")
return "", fmt.Errorf("failed to generate random index: %w", err)
}
result.WriteByte(charset[idx.Int64()])
}
docName := result.String()
log.Debug().
Str("method", "GenerateRandomDocName").
Str("doc_name", docName).
Msg("Generated document name")
return docName, nil
log.Debug().
Str("method", "GenerateRandomDocName").
Int("length", length).
Msg("Generating random document name")
const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
var result strings.Builder
result.Grow(length)
for i := 0; i < length; i++ {
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
log.Error().
Err(err).
Str("method", "GenerateRandomDocName").
Msg("Failed to generate random index")
return "", fmt.Errorf("failed to generate random index: %w", err)
}
result.WriteByte(charset[idx.Int64()])
}
docName := result.String()
log.Debug().
Str("method", "GenerateRandomDocName").
Str("doc_name", docName).
Msg("Generated document name")
return docName, nil
}
// ParseJSONResponse parses a JSON byte slice and extracts the success boolean and data fields as a string.
func ParseJSONResponse(jsonBytes []byte) (success bool, data string, err error) {
log.Debug().
Str("method", "ParseJSONResponse").
Str("json", string(jsonBytes)).
Msg("Parsing JSON response")
// Define struct to capture only the needed fields
type jsonResponse struct {
Success bool `json:"success"`
Data int `json:"data"`
}
var resp jsonResponse
if err := json.Unmarshal(jsonBytes, &resp); err != nil {
log.Error().
Err(err).
Str("method", "ParseJSONResponse").
Msg("Failed to unmarshal JSON")
return false, "", fmt.Errorf("failed to unmarshal JSON: %w", err)
}
dataStr := fmt.Sprintf("%d", resp.Data)
log.Debug().
Str("method", "ParseJSONResponse").
Bool("success", resp.Success).
Str("data", dataStr).
Msg("Parsed JSON response")
return resp.Success, dataStr, nil
log.Debug().
Str("method", "ParseJSONResponse").
Str("json", string(jsonBytes)).
Msg("Parsing JSON response")
// Define struct to capture only the needed fields
type jsonResponse struct {
Success bool `json:"success"`
Data int `json:"data"`
}
var resp jsonResponse
if err := json.Unmarshal(jsonBytes, &resp); err != nil {
log.Error().
Err(err).
Str("method", "ParseJSONResponse").
Msg("Failed to unmarshal JSON")
return false, "", fmt.Errorf("failed to unmarshal JSON: %w", err)
}
dataStr := fmt.Sprintf("%d", resp.Data)
log.Debug().
Str("method", "ParseJSONResponse").
Bool("success", resp.Success).
Str("data", dataStr).
Msg("Parsed JSON response")
return resp.Success, dataStr, nil
}
type IndexReqOption struct {
UserId string
UserName string
UserId string
UserName string
}
const DocNameKey = "doc_name"
// Index implements the Indexer.Index method.
func (ds *docStore) Index(ctx context.Context, req *ai.IndexerRequest) error {
log.Info().
Str("method", "docStore.Index").
Str("space_id", ds.spaceID).
Int("documents", len(req.Documents)).
Msg("Starting index operation")
if len(req.Documents) == 0 {
log.Debug().
Str("method", "docStore.Index").
Str("space_id", ds.spaceID).
Msg("No documents to index")
return nil
}
// Type-assert req.Options to IndexReqOption
opt, ok := req.Options.(*IndexReqOption)
if !ok {
log.Error().
Str("method", "docStore.Index").
Str("options_type", fmt.Sprintf("%T", req.Options)).
Msg("Invalid options type")
return fmt.Errorf("invalid options type: got %T, want *IndexReqOption", req.Options)
}
// Validate required fields
if opt.UserId == "" {
log.Error().Str("method", "docStore.Index").Msg("UserId is required")
return fmt.Errorf("UserId is required in IndexReqOption")
}
if opt.UserName == "" {
log.Error().Str("method", "docStore.Index").Msg("UserName is required")
return fmt.Errorf("UserName is required in IndexReqOption")
}
// Create knowledge space
spaceReq := SpaceRequest{
Name: opt.UserId,
VectorType: "KnowledgeGraph",
DomainType: "Normal",
Desc: opt.UserName,
Owner: opt.UserId,
}
resp, err := ds.client.AddSpace(spaceReq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Index").Msg("Failed to add space")
return fmt.Errorf("add space: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
log.Error().
Str("method", "docStore.Index").
Int("status_code", resp.StatusCode).
Str("response_body", string(body)).
Msg("Add space failed")
return fmt.Errorf("add space failed with status %d: %s", resp.StatusCode, string(body))
}
log.Info().Str("method", "docStore.Index").Str("space_id", opt.UserId).Msg("Space created successfully")
spaceId := opt.UserId
// Index each document
for i, doc := range req.Documents {
// Use DocName from metadata
docName, ok := doc.Metadata[DocNameKey].(string)
if !ok {
log.Error().
Str("method", "docStore.Index").
Int("index", i).
Msg("Missing doc_name in metadata")
return fmt.Errorf("must provide doc_name key in metadata")
}
if docName == "" {
log.Error().
Str("method", "docStore.Index").
Int("index", i).
Msg("doc_name is empty")
return fmt.Errorf("must provide non-empty doc_name str value in metadata")
}
log.Debug().
Str("method", "docStore.Index").
Int("index", i).
Str("doc_name", docName).
Msg("Processing document")
// Add document
var sb strings.Builder
for _, p := range doc.Content {
if p.IsText() {
sb.WriteString(p.Text)
}
}
text := sb.String()
log.Debug().
Str("method", "docStore.Index").
Int("index", i).
Str("text", text).
Msg("Extracted document text")
docReq := DocumentRequest{
DocName: docName,
Source: "api",
DocType: "TEXT",
Content: text,
Labels: "",
Metadata: doc.Metadata,
}
resp, err := ds.client.AddDocument(spaceId, docReq)
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to add document")
return fmt.Errorf("add document %d: %w", i+1, err)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
resp.Body.Close()
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to read add document response")
return fmt.Errorf("read add document response %d: %w", i+1, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Error().
Str("method", "docStore.Index").
Int("index", i+1).
Int("status_code", resp.StatusCode).
Str("response_body", string(body)).
Msg("Add document failed")
return fmt.Errorf("add document %d failed with status %d: %s", i+1, resp.StatusCode, string(body))
}
// Parse AddDocument response
ok, idx, err := ParseJSONResponse(body)
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to parse add document")
return fmt.Errorf("parse add document response %d: %w", i+1, err)
}
if !ok {
log.Error().
Str("method", "docStore.Index").
Int("index", i+1).
log.Info().
Str("method", "docStore.Index").
Str("space_id", ds.spaceID).
Int("documents", len(req.Documents)).
Msg("Starting index operation")
if len(req.Documents) == 0 {
log.Debug().
Str("method", "docStore.Index").
Str("space_id", ds.spaceID).
Msg("No documents to index")
return nil
}
// Type-assert req.Options to IndexReqOption
opt, ok := req.Options.(*IndexReqOption)
if !ok {
log.Error().
Str("method", "docStore.Index").
Str("options_type", fmt.Sprintf("%T", req.Options)).
Msg("Invalid options type")
return fmt.Errorf("invalid options type: got %T, want *IndexReqOption", req.Options)
}
// Validate required fields
if opt.UserId == "" {
log.Error().Str("method", "docStore.Index").Msg("UserId is required")
return fmt.Errorf("UserId is required in IndexReqOption")
}
if opt.UserName == "" {
log.Error().Str("method", "docStore.Index").Msg("UserName is required")
return fmt.Errorf("UserName is required in IndexReqOption")
}
// Create knowledge space
spaceReq := SpaceRequest{
Name: opt.UserId,
VectorType: "KnowledgeGraph",
DomainType: "Normal",
Desc: opt.UserName,
Owner: opt.UserId,
}
resp, err := ds.client.AddSpace(spaceReq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Index").Msg("Failed to add space")
return fmt.Errorf("add space: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
log.Error().
Str("method", "docStore.Index").
Int("status_code", resp.StatusCode).
Str("response_body", string(body)).
Msg("Add space failed")
return fmt.Errorf("add space failed with status %d: %s", resp.StatusCode, string(body))
}
log.Info().Str("method", "docStore.Index").Str("space_id", opt.UserId).Msg("Space created successfully")
spaceId := opt.UserId
// Index each document
for i, doc := range req.Documents {
// Use DocName from metadata
docName, ok := doc.Metadata[DocNameKey].(string)
if !ok {
log.Error().
Str("method", "docStore.Index").
Int("index", i).
Msg("Missing doc_name in metadata")
return fmt.Errorf("must provide doc_name key in metadata")
}
if docName == "" {
log.Error().
Str("method", "docStore.Index").
Int("index", i).
Msg("doc_name is empty")
return fmt.Errorf("must provide non-empty doc_name str value in metadata")
}
log.Debug().
Str("method", "docStore.Index").
Int("index", i).
Str("doc_name", docName).
Msg("Processing document")
// Add document
var sb strings.Builder
for _, p := range doc.Content {
if p.IsText() {
sb.WriteString(p.Text)
}
}
text := sb.String()
log.Debug().
Str("method", "docStore.Index").
Int("index", i).
Str("text", text).
Msg("Extracted document text")
docReq := DocumentRequest{
DocName: docName,
Source: "api",
DocType: "TEXT",
Content: text,
Labels: "",
Metadata: doc.Metadata,
}
resp, err := ds.client.AddDocument(spaceId, docReq)
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to add document")
return fmt.Errorf("add document %d: %w", i+1, err)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
resp.Body.Close()
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to read add document response")
return fmt.Errorf("read add document response %d: %w", i+1, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Error().
Str("method", "docStore.Index").
Int("index", i+1).
Int("status_code", resp.StatusCode).
Str("response_body", string(body)).
Msg("Add document failed")
return fmt.Errorf("add document %d failed with status %d: %s", i+1, resp.StatusCode, string(body))
}
// Parse AddDocument response
ok, idx, err := ParseJSONResponse(body)
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to parse add document")
return fmt.Errorf("parse add document response %d: %w", i+1, err)
}
if !ok {
log.Error().
Str("method", "docStore.Index").
Int("index", i+1).
Str("data", idx).
Msg("Add document response indicated failure")
return fmt.Errorf("add document %d failed: response success=false, data=%s", i+1, idx)
}
log.Info().
Str("method", "docStore.Index").
Int("index", i+1).
Str("doc_id", idx).
Msg("Document added successfully")
// Sync document
_, err = ds.client.SyncDocuments(spaceId, []string{idx})
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to sync document")
return fmt.Errorf("sync document %d: %w", i+1, err)
}
}
log.Info().
Str("method", "docStore.Index").
Str("space_id", ds.spaceID).
Int("documents", len(req.Documents)).
Msg("Index operation completed successfully")
return nil
Msg("Add document response indicated failure")
return fmt.Errorf("add document %d failed: response success=false, data=%s", i+1, idx)
}
log.Info().
Str("method", "docStore.Index").
Int("index", i+1).
Str("doc_id", idx).
Msg("Document added successfully")
// Sync document
_, err = ds.client.SyncDocuments(spaceId, []string{idx})
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Index").
Int("index", i+1).
Msg("Failed to sync document")
return fmt.Errorf("sync document %d: %w", i+1, err)
}
}
log.Info().
Str("method", "docStore.Index").
Str("space_id", ds.spaceID).
Int("documents", len(req.Documents)).
Msg("Index operation completed successfully")
return nil
}
// ChatRequest defines the request structure for chat completions.
type ChatRequest struct {
Model string `json:"model"`
Messages string `json:"messages"`
Temperature float64 `json:"temperature"`
TopP float64 `json:"top_p"`
TopK int `json:"top_k"`
N int `json:"n"`
MaxTokens int64 `json:"max_tokens"`
Stream bool `json:"stream"`
RepetitionPenalty float64 `json:"repetition_penalty"`
FrequencyPenalty float64 `json:"frequency_penalty"`
PresencePenalty float64 `json:"presence_penalty"`
ChatMode string `json:"chat_mode"`
ChatParam string `json:"chat_param"`
EnableVis bool `json:"enable_vis"`
Model string `json:"model"`
Messages string `json:"messages"`
Temperature float64 `json:"temperature"`
TopP float64 `json:"top_p"`
TopK int `json:"top_k"`
N int `json:"n"`
MaxTokens int64 `json:"max_tokens"`
Stream bool `json:"stream"`
RepetitionPenalty float64 `json:"repetition_penalty"`
FrequencyPenalty float64 `json:"frequency_penalty"`
PresencePenalty float64 `json:"presence_penalty"`
ChatMode string `json:"chat_mode"`
ChatParam string `json:"chat_param"`
EnableVis bool `json:"enable_vis"`
}
// ChatResponse defines the response structure from the API.
type ChatResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Index int `json:"index"`
Message struct {
Role string `json:"role"`
Content string `json:"content"`
ReasoningContent interface{} `json:"reasoning_content"`
} `json:"message"`
FinishReason interface{} `json:"finish_reason"`
} `json:"choices"`
Usage struct {
PromptTokens int `json:"prompt_tokens"`
TotalTokens int `json:"total_tokens"`
CompletionTokens int `json:"completion_tokens"`
} `json:"usage"`
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Index int `json:"index"`
Message struct {
Role string `json:"role"`
Content string `json:"content"`
ReasoningContent interface{} `json:"reasoning_content"`
} `json:"message"`
FinishReason interface{} `json:"finish_reason"`
} `json:"choices"`
Usage struct {
PromptTokens int `json:"prompt_tokens"`
TotalTokens int `json:"total_tokens"`
CompletionTokens int `json:"completion_tokens"`
} `json:"usage"`
}
// Assuming ai.Part has a Text() method or Text field to get string content.
func partsToString(parts []*ai.Part) string {
log.Debug().
Str("method", "partsToString").
Int("parts", len(parts)).
Msg("Converting parts to string")
var texts []string
for _, part := range parts {
texts = append(texts, part.Text)
}
result := strings.Join(texts, " ")
log.Debug().
Str("method", "partsToString").
Str("result", result).
Msg("Conversion complete")
return result
log.Debug().
Str("method", "partsToString").
Int("parts", len(parts)).
Msg("Converting parts to string")
var texts []string
for _, part := range parts {
texts = append(texts, part.Text)
}
result := strings.Join(texts, " ")
log.Debug().
Str("method", "partsToString").
Str("result", result).
Msg("Conversion complete")
return result
}
// Retrieve implements the Retriever.Retrieve method.
func (ds *docStore) Retrieve(ctx context.Context, req *ai.RetrieverRequest) (*ai.RetrieverResponse, error) {
log.Info().
Str("method", "docStore.Retrieve").
Str("space_id", ds.spaceID).
Msg("Starting retrieve operation")
// Format query for retrieval.
queryContent := partsToString(req.Query.Content)
queryText := fmt.Sprintf("Search for: %s", queryContent)
log.Debug().
Str("method", "docStore.Retrieve").
Str("query", queryText).
Msg("Formatted query")
if req.Query.Metadata == nil {
log.Error().
Str("method", "docStore.Retrieve").
Str("metadata_type", fmt.Sprintf("%T", req.Query.Metadata)).
Msg("Query metadata is nil")
return nil, fmt.Errorf("req.Query.Metadata must be not nil, got type %T", req.Query.Metadata)
}
for k, v := range req.Query.Metadata {
log.Debug().
Str("method", "docStore.Retrieve").
Str("key", k).
Interface("value", v).
Msg("Metadata entry")
}
// Extract username and user_id from req.Query.Metadata
userName, ok := req.Query.Metadata[util.UserNameKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Msg("Missing username in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide username key")
}
userId, ok := req.Query.Metadata[util.UserIdKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Msg("Missing user_id in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide user_id key")
}
// Prepare request for chat completions endpoint.
url := fmt.Sprintf("%s/api/v2/chat/completions", ds.client.BaseURL)
chatReq := ChatRequest{
Model: ds.modelName,
Messages: queryText,
Temperature: 0.7,
TopP: 1,
TopK: -1,
N: 1,
MaxTokens: 0,
Stream: false,
RepetitionPenalty: 1,
FrequencyPenalty: 0,
PresencePenalty: 0,
ChatMode: "chat_knowledge",
ChatParam: userId,
EnableVis: true,
}
log.Debug().
Str("method", "docStore.Retrieve").
Str("url", url).
Interface("chat_request", chatReq).
Msg("Preparing chat completion request")
body, err := json.Marshal(chatReq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to marshal chat request")
return nil, fmt.Errorf("marshal chat request: %w", err)
}
httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to create chat request")
return nil, fmt.Errorf("create chat request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to send chat request")
return nil, fmt.Errorf("send chat request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
log.Error().
Str("method", "docStore.Retrieve").
Int("status_code", resp.StatusCode).
Str("response_body", string(body)).
Msg("Chat completion failed")
return nil, fmt.Errorf("chat completion failed with status %d: %s", resp.StatusCode, string(body))
}
// Parse response
var chatResp ChatResponse
respBody, err := io.ReadAll(resp.Body)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to read response body")
return nil, fmt.Errorf("read chat response body: %w", err)
}
if err := json.Unmarshal(respBody, &chatResp); err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("raw_response", string(respBody)).
Msg("Failed to decode chat response")
return nil, fmt.Errorf("decode chat response: %w, raw response: %s", err, string(respBody))
}
log.Debug().
Str("method", "docStore.Retrieve").
Interface("chat_response", chatResp).
Msg("Parsed chat response")
// Convert response to ai.Document
var docs []*ai.Document
if len(chatResp.Choices) > 0 {
content := chatResp.Choices[0].Message.Content
metadata := map[string]interface{}{
util.UserIdKey: userId,
util.UserNameKey: userName,
}
aiDoc := ai.DocumentFromText(content, metadata)
docs = append(docs, aiDoc)
log.Debug().
Str("method", "docStore.Retrieve").
Str("content", content).
Interface("metadata", metadata).
Msg("Created document from response")
}
log.Info().
Str("method", "docStore.Retrieve").
Str("space_id", ds.spaceID).
Int("documents", len(docs)).
Msg("Retrieve operation completed successfully")
return &ai.RetrieverResponse{
Documents: docs,
}, nil
log.Info().
Str("method", "docStore.Retrieve").
Str("space_id", ds.spaceID).
Msg("Starting retrieve operation")
// Format query for retrieval.
queryContent := partsToString(req.Query.Content)
queryText := fmt.Sprintf("Search for: %s", queryContent)
log.Debug().
Str("method", "docStore.Retrieve").
Str("query", queryText).
Msg("Formatted query")
if req.Query.Metadata == nil {
log.Error().
Str("method", "docStore.Retrieve").
Str("metadata_type", fmt.Sprintf("%T", req.Query.Metadata)).
Msg("Query metadata is nil")
return nil, fmt.Errorf("req.Query.Metadata must be not nil, got type %T", req.Query.Metadata)
}
for k, v := range req.Query.Metadata {
log.Debug().
Str("method", "docStore.Retrieve").
Str("key", k).
Interface("value", v).
Msg("Metadata entry")
}
// Extract username and user_id from req.Query.Metadata
userName, ok := req.Query.Metadata[util.UserNameKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Msg("Missing username in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide username key")
}
userId, ok := req.Query.Metadata[util.UserIdKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Msg("Missing user_id in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide user_id key")
}
// Prepare request for chat completions endpoint.
url := fmt.Sprintf("%s/api/v2/chat/completions", ds.client.BaseURL)
chatReq := ChatRequest{
Model: ds.modelName,
Messages: queryText,
Temperature: 0.7,
TopP: 1,
TopK: -1,
N: 1,
MaxTokens: 0,
Stream: false,
RepetitionPenalty: 1,
FrequencyPenalty: 0,
PresencePenalty: 0,
ChatMode: "chat_knowledge",
ChatParam: userId,
EnableVis: true,
}
log.Debug().
Str("method", "docStore.Retrieve").
Str("url", url).
Interface("chat_request", chatReq).
Msg("Preparing chat completion request")
body, err := json.Marshal(chatReq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to marshal chat request")
return nil, fmt.Errorf("marshal chat request: %w", err)
}
httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to create chat request")
return nil, fmt.Errorf("create chat request: %w", err)
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to send chat request")
return nil, fmt.Errorf("send chat request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
log.Error().
Str("method", "docStore.Retrieve").
Int("status_code", resp.StatusCode).
Str("response_body", string(body)).
Msg("Chat completion failed")
return nil, fmt.Errorf("chat completion failed with status %d: %s", resp.StatusCode, string(body))
}
// Parse response
var chatResp ChatResponse
respBody, err := io.ReadAll(resp.Body)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Msg("Failed to read response body")
return nil, fmt.Errorf("read chat response body: %w", err)
}
if err := json.Unmarshal(respBody, &chatResp); err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("raw_response", string(respBody)).
Msg("Failed to decode chat response")
return nil, fmt.Errorf("decode chat response: %w, raw response: %s", err, string(respBody))
}
log.Debug().
Str("method", "docStore.Retrieve").
Interface("chat_response", chatResp).
Msg("Parsed chat response")
// Convert response to ai.Document
var docs []*ai.Document
if len(chatResp.Choices) > 0 {
content := chatResp.Choices[0].Message.Content
metadata := map[string]interface{}{
util.UserIdKey: userId,
util.UserNameKey: userName,
}
aiDoc := ai.DocumentFromText(content, metadata)
docs = append(docs, aiDoc)
log.Debug().
Str("method", "docStore.Retrieve").
Str("content", content).
Interface("metadata", metadata).
Msg("Created document from response")
}
log.Info().
Str("method", "docStore.Retrieve").
Str("space_id", ds.spaceID).
Int("documents", len(docs)).
Msg("Retrieve operation completed successfully")
return &ai.RetrieverResponse{
Documents: docs,
}, nil
}
// // Copyright 2025 Google LLC
// //
// // Licensed under the Apache License, Version 2.0 (the "License");
......
......@@ -10,41 +10,40 @@ import (
)
func main() {
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性
// 以下代码示例仅供参考,建议采用更安全的方式来使用密钥
// 请参见:https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性
// 以下代码示例仅供参考,建议采用更安全的方式来使用密钥
// 请参见:https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
//os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
//os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
//os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
//os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
credential := common.NewCredential(
"AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF",
"rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd",
)
// 使用临时密钥示例
// credential := common.NewTokenCredential("SecretId", "SecretKey", "Token")
// 实例化一个client选项,可选的,没有特殊需求可以跳过
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "lkeap.tencentcloudapi.com"
// 实例化要请求产品的client对象,clientProfile是可选的
client, _ := lkeap.NewClient(credential, "ap-guangzhou", cpf)
credential := common.NewCredential(
"AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF",
"rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd",
)
// 使用临时密钥示例
// credential := common.NewTokenCredential("SecretId", "SecretKey", "Token")
// 实例化一个client选项,可选的,没有特殊需求可以跳过
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "lkeap.tencentcloudapi.com"
// 实例化要请求产品的client对象,clientProfile是可选的
client, _ := lkeap.NewClient(credential, "ap-guangzhou", cpf)
// 实例化一个请求对象,每个接口都会对应一个request对象
request := lkeap.NewQueryRewriteRequest()
// 实例化一个请求对象,每个接口都会对应一个request对象
request := lkeap.NewQueryRewriteRequest()
request.Model = common.StringPtr("*")
// 返回的resp是一个QueryRewriteResponse的实例,与请求对象对应
response, err := client.QueryRewrite(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Printf("An API error has returned: %s", err)
return
}
if err != nil {
panic(err)
}
// 输出json格式的字符串回包
fmt.Printf("%s", response.ToJsonString())
}
\ No newline at end of file
request.Model = common.StringPtr("*")
// 返回的resp是一个QueryRewriteResponse的实例,与请求对象对应
response, err := client.QueryRewrite(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Printf("An API error has returned: %s", err)
return
}
if err != nil {
panic(err)
}
// 输出json格式的字符串回包
fmt.Printf("%s", response.ToJsonString())
}
// // Copyright 2025
// //
// // Licensed under the Apache License, Version 2.0 (the "License");
// // you may not use this file except in compliance with the License.
// // You may obtain a copy of the License at
// //
// // http://www.apache.org/licenses/LICENSE-2.0
// //
// // Unless required by applicable law or agreed to in writing, software
// // distributed under the License is distributed on an "AS IS" BASIS,
// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// // See the License for the specific language governing permissions and
// // limitations under the License.
// //
// // SPDX-License-Identifier: Apache-2.0
// package knowledge
// import (
// "context"
// "encoding/json"
// "fmt"
// "os"
// "strings"
// "sync"
// "github.com/rs/zerolog/log"
// "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
// "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
// "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
// lkeap "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lkeap/v20240522"
// )
// // ClientConfig holds configuration options for the Tencent Cloud LKEAP client.
// type ClientConfig struct {
// SecretID string // Tencent Cloud Secret ID
// SecretKey string // Tencent Cloud Secret Key
// Token string // Optional: Temporary token for authentication
// Endpoint string // API endpoint (default: lkeap.tencentcloudapi.com)
// Region string // Tencent Cloud region (optional)
// }
// // KnowledgeClient manages interactions with the Tencent Cloud LKEAP API.
// type KnowledgeClient struct {
// client *lkeap.Client
// config ClientConfig
// mu sync.Mutex
// initted bool
// }
// // NewKnowledgeClient creates a new KnowledgeClient with the given configuration.
// func NewKnowledgeClient(config ClientConfig) *KnowledgeClient {
// log.Info().
// Str("method", "NewKnowledgeClient").
// Str("endpoint", config.Endpoint).
// Str("region", config.Region).
// Str("secret_id", maskCredential(config.SecretID)).
// Str("token", maskCredential(config.Token)).
// Msg("Creating new KnowledgeClient")
// return &KnowledgeClient{
// config: config,
// }
// }
// // Init initializes the KnowledgeClient.
// func (kc *KnowledgeClient) Init(ctx context.Context) error {
// log.Info().Str("method", "KnowledgeClient.Init").Msg("Initializing KnowledgeClient")
// kc.mu.Lock()
// defer kc.mu.Unlock()
// if kc.initted {
// log.Error().Str("method", "KnowledgeClient.Init").Msg("Client already initialized")
// return fmt.Errorf("knowledge client already initialized")
// }
// // Load configuration from environment variables if not set
// if kc.config.SecretID == "" {
// kc.config.SecretID = os.Getenv("TENCENTCLOUD_SECRET_ID")
// }
// if kc.config.SecretKey == "" {
// kc.config.SecretKey = os.Getenv("TENCENTCLOUD_SECRET_KEY")
// }
// if kc.config.Token == "" {
// kc.config.Token = os.Getenv("TENCENTCLOUD_TOKEN")
// }
// if kc.config.Endpoint == "" {
// kc.config.Endpoint = "lkeap.tencentcloudapi.com"
// }
// if kc.config.Region == "" {
// kc.config.Region = "ap-guangzhou"
// }
// // Validate configuration
// if kc.config.SecretID == "" || kc.config.SecretKey == "" {
// log.Error().Str("method", "KnowledgeClient.Init").Msg("SecretID and SecretKey are required")
// return fmt.Errorf("knowledge: SecretID and SecretKey are required")
// }
// // Create credential
// var credential *common.Credential
// if kc.config.Token != "" {
// credential = common.NewTokenCredential(kc.config.SecretID, kc.config.SecretKey, kc.config.Token)
// log.Debug().Str("method", "KnowledgeClient.Init").Msg("Using temporary token credential")
// } else {
// credential = common.NewCredential(kc.config.SecretID, kc.config.SecretKey)
// log.Debug().Str("method", "KnowledgeClient.Init").Msg("Using standard credential")
// }
// // Create client profile
// cpf := profile.NewClientProfile()
// cpf.HttpProfile.Endpoint = kc.config.Endpoint
// // Initialize client
// client, err := lkeap.NewClient(credential, kc.config.Region, cpf)
// if err != nil {
// log.Error().
// Err(err).
// Str("method", "KnowledgeClient.Init").
// Msg("Failed to create LKEAP client")
// return err
// }
// kc.client = client
// kc.initted = true
// log.Info().Str("method", "KnowledgeClient.Init").Msg("Initialization successful")
// return nil
// }
// // QueryRewriteRequest defines the input for a query rewrite operation.
// type QueryRewriteRequest struct {
// Messages []*lkeap.Message // Multi-turn conversation history (up to 4 turns)
// Model string // Model name for query rewriting
// }
// // QueryRewriteResponse defines the output of a query rewrite operation.
// type QueryRewriteResponse struct {
// RewrittenQuery string // The rewritten query
// RawResponse *lkeap.QueryRewriteResponse
// }
// // QueryRewrite performs a query rewrite using the Tencent Cloud LKEAP API.
// func (kc *KnowledgeClient) QueryRewrite(ctx context.Context, req QueryRewriteRequest) (*QueryRewriteResponse, error) {
// log.Info().
// Str("method", "KnowledgeClient.QueryRewrite").
// Int("message_count", len(req.Messages)).
// Str("model", req.Model).
// Msg("Starting query rewrite operation")
// if !kc.initted {
// log.Error().Str("method", "KnowledgeClient.QueryRewrite").Msg("Client not initialized")
// return nil, fmt.Errorf("knowledge client not initialized; call Init first")
// }
// // Validate input
// if len(req.Messages) == 0 {
// log.Error().Str("method", "KnowledgeClient.QueryRewrite").Msg("At least one message is required")
// return nil, fmt.Errorf("at least one message is required")
// }
// if len(req.Messages) > 4 {
// log.Warn().
// Str("method", "KnowledgeClient.QueryRewrite").
// Int("message_count", len(req.Messages)).
// Msg("Message count exceeds 4, truncating to 4")
// req.Messages = req.Messages[:4]
// }
// for i, msg := range req.Messages {
// if msg.Role == nil || *msg.Role == "" {
// log.Error().
// Str("method", "KnowledgeClient.QueryRewrite").
// Int("index", i).
// Msg("Role is required in each message")
// return nil, fmt.Errorf("message at index %d missing role", i)
// }
// if *msg.Role != "user" && *msg.Role != "assistant" {
// log.Error().
// Str("method", "KnowledgeClient.QueryRewrite").
// Int("index", i).
// Str("role", *msg.Role).
// Msg("Invalid role; must be 'user' or 'assistant'")
// return nil, fmt.Errorf("invalid role '%s' at index %d", *msg.Role, i)
// }
// if msg.Content == nil || *msg.Content == "" {
// log.Error().
// Str("method", "KnowledgeClient.QueryRewrite").
// Int("index", i).
// Msg("Content is required in each message")
// return nil, fmt.Errorf("message at index %d missing content", i)
// }
// log.Debug().
// Str("method", "KnowledgeClient.QueryRewrite").
// Int("index", i).
// Str("role", *msg.Role).
// Str("content", *msg.Content).
// Msg("Validated message")
// }
// if req.Model == "" {
// log.Warn().Str("method", "KnowledgeClient.QueryRewrite").Msg("Model not specified, using default")
// req.Model = "lke-query-rewrite-base"
// }
// // Create Tencent Cloud request
// tencentReq := lkeap.NewQueryRewriteRequest()
// tencentReq.Messages = req.Messages
// if req.Model != "" {
// tencentReq.Model = common.StringPtr(req.Model)
// }
// // Debug request
// tencentReqAsJson, _ := json.Marshal(tencentReq)
// log.Debug().
// Str("method", "KnowledgeClient.QueryRewrite").
// Str("request_json", string(tencentReqAsJson)).
// Msg("Prepared Tencent Cloud request")
// // Perform request
// response, err := kc.client.QueryRewriteWithContext(ctx, tencentReq)
// if err != nil {
// if _, ok := err.(*errors.TencentCloudSDKError); ok {
// log.Error().
// Err(err).
// Str("method", "KnowledgeClient.QueryRewrite").
// Msg("Tencent Cloud API error")
// return nil, fmt.Errorf("tencent cloud api error: %w", err)
// }
// log.Error().
// Err(err).
// Str("method", "KnowledgeClient.QueryRewrite").
// Msg("Failed to perform query rewrite")
// return nil, fmt.Errorf("query rewrite failed: %w", err)
// }
// // Extract response fields
// var rewrittenQuery string
// var requestId string
// if response.Response.Content != nil {
// rewrittenQuery = *response.Response.Content
// }
// if response.Response.RequestId != nil {
// requestId = *response.Response.RequestId
// }
// result := &QueryRewriteResponse{
// RewrittenQuery: rewrittenQuery,
// RawResponse: response,
// }
// log.Info().
// Str("method", "KnowledgeClient.QueryRewrite").
// Str("rewritten_query", rewrittenQuery).
// Str("request_id", requestId).
// Interface("usage", response.Response.Usage).
// Str("raw_response", response.ToJsonString()).
// Msg("Query rewrite operation completed successfully")
// return result, nil
// }
// // QueryRewriteWithSummary wraps QueryRewrite to handle a user question, assistant answer, and history summary.
// func (kc *KnowledgeClient) QueryRewriteWithSummary(ctx context.Context, userQuestion, assistantAnswer, historySummary string) (*QueryRewriteResponse, error) {
// log.Info().
// Str("method", "KnowledgeClient.QueryRewriteWithSummary").
// Str("user_question", userQuestion).
// Str("assistant_answer", assistantAnswer).
// Str("history_summary", historySummary).
// Msg("Starting query rewrite with summary operation")
// if userQuestion == "" || assistantAnswer == "" {
// log.Error().Str("method", "KnowledgeClient.QueryRewriteWithSummary").Msg("User question and assistant answer are required")
// return nil, fmt.Errorf("user question and assistant answer are required")
// }
// // Construct messages
// messages := []*lkeap.Message{
// {
// Role: common.StringPtr("user"),
// Content: common.StringPtr(userQuestion),
// },
// {
// Role: common.StringPtr("assistant"),
// Content: common.StringPtr(assistantAnswer),
// },
// }
// // Append history summary as an assistant message if provided
// if historySummary != "" {
// messages = append(messages, &lkeap.Message{
// Role: common.StringPtr("assistant"),
// Content: common.StringPtr(fmt.Sprintf("Conversation summary: %s", historySummary)),
// })
// }
// // Create request
// req := QueryRewriteRequest{
// Messages: messages,
// Model: "lke-query-rewrite-base",
// }
// // Call QueryRewrite
// return kc.QueryRewrite(ctx, req)
// }
// // maskCredential masks sensitive credentials for logging
// func maskCredential(cred string) string {
// if len(cred) <= 8 {
// return strings.Repeat("*", len(cred))
// }
// return cred[:4] + strings.Repeat("*", len(cred)-8) + cred[len(cred)-4:]
// }
// Copyright 2025
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
package knowledge
import (
......@@ -341,278 +17,275 @@ import (
// ClientConfig holds configuration options for the Tencent Cloud LKEAP client.
type ClientConfig struct {
SecretID string // Tencent Cloud Secret ID
SecretKey string // Tencent Cloud Secret Key
Token string // Optional: Temporary token for authentication
Endpoint string // API endpoint (default: lkeap.tencentcloudapi.com)
Region string // Tencent Cloud region (optional)
SecretID string // Tencent Cloud Secret ID
SecretKey string // Tencent Cloud Secret Key
Token string // Optional: Temporary token for authentication
Endpoint string // API endpoint (default: lkeap.tencentcloudapi.com)
Region string // Tencent Cloud region (optional)
}
// KnowledgeClient manages interactions with the Tencent Cloud LKEAP API.
type KnowledgeClient struct {
client *lkeap.Client
config ClientConfig
mu sync.Mutex
initted bool
client *lkeap.Client
config ClientConfig
mu sync.Mutex
initted bool
}
// NewKnowledgeClient creates a new KnowledgeClient with the given configuration.
func NewKnowledgeClient(config ClientConfig) *KnowledgeClient {
log.Info().
Str("method", "NewKnowledgeClient").
Str("endpoint", config.Endpoint).
Str("region", config.Region).
Str("secret_id", maskCredential(config.SecretID)).
Str("token", maskCredential(config.Token)).
Msg("Creating new KnowledgeClient")
return &KnowledgeClient{
config: config,
}
log.Info().
Str("method", "NewKnowledgeClient").
Str("endpoint", config.Endpoint).
Str("region", config.Region).
Str("secret_id", maskCredential(config.SecretID)).
Str("token", maskCredential(config.Token)).
Msg("Creating new KnowledgeClient")
return &KnowledgeClient{
config: config,
}
}
// Init initializes the KnowledgeClient.
func (kc *KnowledgeClient) Init(ctx context.Context) error {
log.Info().Str("method", "KnowledgeClient.Init").Msg("Initializing KnowledgeClient")
kc.mu.Lock()
defer kc.mu.Unlock()
if kc.initted {
log.Error().Str("method", "KnowledgeClient.Init").Msg("Client already initialized")
return fmt.Errorf("knowledge client already initialized")
}
// Load configuration from environment variables if not set
if kc.config.SecretID == "" {
kc.config.SecretID = os.Getenv("TENCENTCLOUD_SECRET_ID")
}
if kc.config.SecretKey == "" {
kc.config.SecretKey = os.Getenv("TENCENTCLOUD_SECRET_KEY")
}
if kc.config.Token == "" {
kc.config.Token = os.Getenv("TENCENTCLOUD_TOKEN")
}
if kc.config.Endpoint == "" {
kc.config.Endpoint = "lkeap.tencentcloudapi.com"
}
if kc.config.Region == "" {
kc.config.Region = "ap-guangzhou" // Default to ap-guangzhou as per curl
}
// Validate configuration
if kc.config.SecretID == "" || kc.config.SecretKey == "" {
log.Error().Str("method", "KnowledgeClient.Init").Msg("SecretID and SecretKey are required")
return fmt.Errorf("knowledge: SecretID and SecretKey are required")
}
// Create credential
var credential *common.Credential
if kc.config.Token != "" {
credential = common.NewTokenCredential(kc.config.SecretID, kc.config.SecretKey, kc.config.Token)
log.Debug().Str("method", "KnowledgeClient.Init").Msg("Using temporary token credential")
} else {
credential = common.NewCredential(kc.config.SecretID, kc.config.SecretKey)
log.Debug().Str("method", "KnowledgeClient.Init").Msg("Using standard credential")
}
// Create client profile
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = kc.config.Endpoint
// Initialize client
client, err := lkeap.NewClient(credential, kc.config.Region, cpf)
if err != nil {
log.Error().
Err(err).
Str("method", "KnowledgeClient.Init").
Msg("Failed to create LKEAP client")
return err
}
kc.client = client
kc.initted = true
log.Info().Str("method", "KnowledgeClient.Init").Msg("Initialization successful")
return nil
log.Info().Str("method", "KnowledgeClient.Init").Msg("Initializing KnowledgeClient")
kc.mu.Lock()
defer kc.mu.Unlock()
if kc.initted {
log.Error().Str("method", "KnowledgeClient.Init").Msg("Client already initialized")
return fmt.Errorf("knowledge client already initialized")
}
// Load configuration from environment variables if not set
if kc.config.SecretID == "" {
kc.config.SecretID = os.Getenv("TENCENTCLOUD_SECRET_ID")
}
if kc.config.SecretKey == "" {
kc.config.SecretKey = os.Getenv("TENCENTCLOUD_SECRET_KEY")
}
if kc.config.Token == "" {
kc.config.Token = os.Getenv("TENCENTCLOUD_TOKEN")
}
if kc.config.Endpoint == "" {
kc.config.Endpoint = "lkeap.tencentcloudapi.com"
}
if kc.config.Region == "" {
kc.config.Region = "ap-guangzhou" // Default to ap-guangzhou as per curl
}
// Validate configuration
if kc.config.SecretID == "" || kc.config.SecretKey == "" {
log.Error().Str("method", "KnowledgeClient.Init").Msg("SecretID and SecretKey are required")
return fmt.Errorf("knowledge: SecretID and SecretKey are required")
}
// Create credential
var credential *common.Credential
if kc.config.Token != "" {
credential = common.NewTokenCredential(kc.config.SecretID, kc.config.SecretKey, kc.config.Token)
log.Debug().Str("method", "KnowledgeClient.Init").Msg("Using temporary token credential")
} else {
credential = common.NewCredential(kc.config.SecretID, kc.config.SecretKey)
log.Debug().Str("method", "KnowledgeClient.Init").Msg("Using standard credential")
}
// Create client profile
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = kc.config.Endpoint
// Initialize client
client, err := lkeap.NewClient(credential, kc.config.Region, cpf)
if err != nil {
log.Error().
Err(err).
Str("method", "KnowledgeClient.Init").
Msg("Failed to create LKEAP client")
return err
}
kc.client = client
kc.initted = true
log.Info().Str("method", "KnowledgeClient.Init").Msg("Initialization successful")
return nil
}
// QueryRewriteRequest defines the input for a query rewrite operation.
type QueryRewriteRequest struct {
Messages []*lkeap.Message // Multi-turn conversation history (up to 4 turns)
Model string // Model name for query rewriting
Messages []*lkeap.Message // Multi-turn conversation history (up to 4 turns)
Model string // Model name for query rewriting
}
// QueryRewriteResponse defines the output of a query rewrite operation.
type QueryRewriteResponse struct {
RewrittenQuery string // The rewritten query
RawResponse *lkeap.QueryRewriteResponse
RewrittenQuery string // The rewritten query
RawResponse *lkeap.QueryRewriteResponse
}
// QueryRewrite performs a query rewrite using the Tencent Cloud LKEAP API.
func (kc *KnowledgeClient) QueryRewrite(ctx context.Context, req QueryRewriteRequest) (*QueryRewriteResponse, error) {
log.Info().
Str("method", "KnowledgeClient.QueryRewrite").
Int("message_count", len(req.Messages)).
Str("model", req.Model).
Msg("Starting query rewrite operation")
if !kc.initted {
log.Error().Str("method", "KnowledgeClient.QueryRewrite").Msg("Client not initialized")
return nil, fmt.Errorf("knowledge client not initialized; call Init first")
}
// Validate input
if len(req.Messages) == 0 {
log.Error().Str("method", "KnowledgeClient.QueryRewrite").Msg("At least one message is required")
return nil, fmt.Errorf("at least one message is required")
}
if len(req.Messages) > 4 {
log.Warn().
Str("method", "KnowledgeClient.QueryRewrite").
Int("message_count", len(req.Messages)).
Msg("Message count exceeds 4, truncating to 4")
req.Messages = req.Messages[:4]
}
for i, msg := range req.Messages {
if msg.Role == nil || *msg.Role == "" {
log.Error().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Msg("Role is required in each message")
return nil, fmt.Errorf("message at index %d missing role", i)
}
if *msg.Role != "user" && *msg.Role != "assistant" {
log.Error().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Str("role", *msg.Role).
Msg("Invalid role; must be 'user' or 'assistant'")
return nil, fmt.Errorf("invalid role '%s' at index %d", *msg.Role, i)
}
if msg.Content == nil || *msg.Content == "" {
log.Error().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Msg("Content is required in each message")
return nil, fmt.Errorf("message at index %d missing content", i)
}
log.Debug().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Str("role", *msg.Role).
Str("content", *msg.Content).
Msg("Validated message")
}
if req.Model == "" {
log.Warn().Str("method", "KnowledgeClient.QueryRewrite").Msg("Model not specified, using default")
req.Model = "lke-query-rewrite-base" // Default as per curl
}
// Create Tencent Cloud request
tencentReq := lkeap.NewQueryRewriteRequest()
tencentReq.Messages = req.Messages
if req.Model != "" {
tencentReq.Model = common.StringPtr(req.Model)
}
// Debug request
tencentReqAsJson, _ := json.Marshal(tencentReq)
log.Debug().
Str("method", "KnowledgeClient.QueryRewrite").
Str("request_json", string(tencentReqAsJson)).
Msg("Prepared Tencent Cloud request")
// Perform request
response, err := kc.client.QueryRewriteWithContext(ctx, tencentReq)
if err != nil {
if _, ok := err.(*errors.TencentCloudSDKError); ok {
log.Error().
Err(err).
Str("method", "KnowledgeClient.QueryRewrite").
Msg("Tencent Cloud API error")
return nil, fmt.Errorf("tencent cloud api error: %w", err)
}
log.Error().
Err(err).
Str("method", "KnowledgeClient.QueryRewrite").
Msg("Failed to perform query rewrite")
return nil, fmt.Errorf("query rewrite failed: %w", err)
}
// Extract response fields
var rewrittenQuery string
var requestId string
if response.Response.Content != nil {
rewrittenQuery = *response.Response.Content
}
if response.Response.RequestId != nil {
requestId = *response.Response.RequestId
}
result := &QueryRewriteResponse{
RewrittenQuery: rewrittenQuery,
RawResponse: response,
}
log.Info().
Str("method", "KnowledgeClient.QueryRewrite").
Str("rewritten_query", rewrittenQuery).
Str("request_id", requestId).
Interface("usage", response.Response.Usage).
Str("raw_response", response.ToJsonString()).
Msg("Query rewrite operation completed successfully")
return result, nil
log.Info().
Str("method", "KnowledgeClient.QueryRewrite").
Int("message_count", len(req.Messages)).
Str("model", req.Model).
Msg("Starting query rewrite operation")
if !kc.initted {
log.Error().Str("method", "KnowledgeClient.QueryRewrite").Msg("Client not initialized")
return nil, fmt.Errorf("knowledge client not initialized; call Init first")
}
// Validate input
if len(req.Messages) == 0 {
log.Error().Str("method", "KnowledgeClient.QueryRewrite").Msg("At least one message is required")
return nil, fmt.Errorf("at least one message is required")
}
if len(req.Messages) > 4 {
log.Warn().
Str("method", "KnowledgeClient.QueryRewrite").
Int("message_count", len(req.Messages)).
Msg("Message count exceeds 4, truncating to 4")
req.Messages = req.Messages[:4]
}
for i, msg := range req.Messages {
if msg.Role == nil || *msg.Role == "" {
log.Error().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Msg("Role is required in each message")
return nil, fmt.Errorf("message at index %d missing role", i)
}
if *msg.Role != "user" && *msg.Role != "assistant" {
log.Error().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Str("role", *msg.Role).
Msg("Invalid role; must be 'user' or 'assistant'")
return nil, fmt.Errorf("invalid role '%s' at index %d", *msg.Role, i)
}
if msg.Content == nil || *msg.Content == "" {
log.Error().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Msg("Content is required in each message")
return nil, fmt.Errorf("message at index %d missing content", i)
}
log.Debug().
Str("method", "KnowledgeClient.QueryRewrite").
Int("index", i).
Str("role", *msg.Role).
Str("content", *msg.Content).
Msg("Validated message")
}
if req.Model == "" {
log.Warn().Str("method", "KnowledgeClient.QueryRewrite").Msg("Model not specified, using default")
req.Model = "lke-query-rewrite-base" // Default as per curl
}
// Create Tencent Cloud request
tencentReq := lkeap.NewQueryRewriteRequest()
tencentReq.Messages = req.Messages
if req.Model != "" {
tencentReq.Model = common.StringPtr(req.Model)
}
// Debug request
tencentReqAsJson, _ := json.Marshal(tencentReq)
log.Debug().
Str("method", "KnowledgeClient.QueryRewrite").
Str("request_json", string(tencentReqAsJson)).
Msg("Prepared Tencent Cloud request")
// Perform request
response, err := kc.client.QueryRewriteWithContext(ctx, tencentReq)
if err != nil {
if _, ok := err.(*errors.TencentCloudSDKError); ok {
log.Error().
Err(err).
Str("method", "KnowledgeClient.QueryRewrite").
Msg("Tencent Cloud API error")
return nil, fmt.Errorf("tencent cloud api error: %w", err)
}
log.Error().
Err(err).
Str("method", "KnowledgeClient.QueryRewrite").
Msg("Failed to perform query rewrite")
return nil, fmt.Errorf("query rewrite failed: %w", err)
}
// Extract response fields
var rewrittenQuery string
var requestId string
if response.Response.Content != nil {
rewrittenQuery = *response.Response.Content
}
if response.Response.RequestId != nil {
requestId = *response.Response.RequestId
}
result := &QueryRewriteResponse{
RewrittenQuery: rewrittenQuery,
RawResponse: response,
}
log.Info().
Str("method", "KnowledgeClient.QueryRewrite").
Str("rewritten_query", rewrittenQuery).
Str("request_id", requestId).
Interface("usage", response.Response.Usage).
Str("raw_response", response.ToJsonString()).
Msg("Query rewrite operation completed successfully")
return result, nil
}
// maskCredential masks sensitive credentials for logging
func maskCredential(cred string) string {
if len(cred) <= 8 {
return strings.Repeat("*", len(cred))
}
return cred[:4] + strings.Repeat("*", len(cred)-8) + cred[len(cred)-4:]
if len(cred) <= 8 {
return strings.Repeat("*", len(cred))
}
return cred[:4] + strings.Repeat("*", len(cred)-8) + cred[len(cred)-4:]
}
// QueryRewriteWithSummary wraps QueryRewrite to handle a user question, assistant answer, and history summary.
func (kc *KnowledgeClient) QueryRewriteWithSummary(ctx context.Context, userQuestion, assistantAnswer, historySummary string) (*QueryRewriteResponse, error) {
log.Info().
Str("method", "KnowledgeClient.QueryRewriteWithSummary").
Str("user_question", userQuestion).
Str("assistant_answer", assistantAnswer).
Str("history_summary", historySummary).
Msg("Starting query rewrite with summary operation")
if userQuestion == "" || assistantAnswer == "" {
log.Error().Str("method", "KnowledgeClient.QueryRewriteWithSummary").Msg("User question and assistant answer are required")
return nil, fmt.Errorf("user question and assistant answer are required")
}
// Construct messages
messages := []*lkeap.Message{
{
Role: common.StringPtr("user"),
Content: common.StringPtr(userQuestion),
},
{
Role: common.StringPtr("assistant"),
Content: common.StringPtr(assistantAnswer),
},
}
// Append history summary as an assistant message if provided
if historySummary != "" {
messages = append(messages, &lkeap.Message{
Role: common.StringPtr("user"),
Content: common.StringPtr(fmt.Sprintf("Conversation summary: %s", historySummary)),
})
}
// Create request
req := QueryRewriteRequest{
Messages: messages,
Model: "lke-query-rewrite-base",
}
// Call QueryRewrite
return kc.QueryRewrite(ctx, req)
log.Info().
Str("method", "KnowledgeClient.QueryRewriteWithSummary").
Str("user_question", userQuestion).
Str("assistant_answer", assistantAnswer).
Str("history_summary", historySummary).
Msg("Starting query rewrite with summary operation")
if userQuestion == "" || assistantAnswer == "" {
log.Error().Str("method", "KnowledgeClient.QueryRewriteWithSummary").Msg("User question and assistant answer are required")
return nil, fmt.Errorf("user question and assistant answer are required")
}
// Construct messages
messages := []*lkeap.Message{
{
Role: common.StringPtr("user"),
Content: common.StringPtr(userQuestion),
},
{
Role: common.StringPtr("assistant"),
Content: common.StringPtr(assistantAnswer),
},
}
// Append history summary as an assistant message if provided
if historySummary != "" {
messages = append(messages, &lkeap.Message{
Role: common.StringPtr("user"),
Content: common.StringPtr(fmt.Sprintf("Conversation summary: %s", historySummary)),
})
}
// Create request
req := QueryRewriteRequest{
Messages: messages,
Model: "lke-query-rewrite-base",
}
// Call QueryRewrite
return kc.QueryRewrite(ctx, req)
}
// // Copyright 2025
// //
// // Licensed under the Apache License, Version 2.0 (the "License");
// // you may not use this file except in compliance with the License.
// // You may obtain a copy of the License at
// //
// // http://www.apache.org/licenses/LICENSE-2.0
// //
// // Unless required by applicable law or agreed to in writing, software
// // distributed under the License is distributed on an "AS IS" BASIS,
// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// // See the License for the specific language governing permissions and
// // limitations under the License.
// //
// // SPDX-License-Identifier: Apache-2.0
// package knowledge
// import (
// "context"
// "os"
// "testing"
// "github.com/rs/zerolog"
// "github.com/rs/zerolog/log"
// "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
// lkeap "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lkeap/v20240522"
// )
// func TestMain(m *testing.M) {
// // Configure zerolog for human-readable console output during tests
// zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
// log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
// // Run tests
// os.Exit(m.Run())
// }
// func TestKnowledgeClient_QueryRewrite(t *testing.T) {
// // Warning: Do not hardcode credentials in production code. Use environment variables or a secure vault.
// os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
// os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
// defer func() {
// os.Unsetenv("TENCENTCLOUD_SECRET_ID")
// os.Unsetenv("TENCENTCLOUD_SECRET_KEY")
// }()
// // Create client configuration
// config := ClientConfig{
// Endpoint: "lkeap.tencentcloudapi.com",
// Region: "ap-guangzhou",
// }
// // Initialize client
// client := NewKnowledgeClient(config)
// ctx := context.Background()
// // Test cases
// tests := []struct {
// name string
// messages []*lkeap.Message
// model string
// expectError bool
// }{
// {
// name: "CurlPayload",
// messages: []*lkeap.Message{
// {
// Role: common.StringPtr("user"),
// Content: common.StringPtr("你的家在哪里"),
// },
// {
// Role: common.StringPtr("assistant"),
// Content: common.StringPtr("国内"),
// },
// {
// Role: common.StringPtr("user"),
// Content: common.StringPtr("国内哪里"),
// },
// },
// model: "lke-query-rewrite-base",
// expectError: true,
// },
// {
// name: "ValidMultiTurnConversation",
// messages: []*lkeap.Message{
// {
// Role: common.StringPtr("user"),
// Content: common.StringPtr("What is the capital of France?"),
// },
// {
// Role: common.StringPtr("assistant"),
// Content: common.StringPtr("The capital of France is Paris."),
// },
// {
// Role: common.StringPtr("user"),
// Content: common.StringPtr("Tell me more about Paris."),
// },
// {
// Role: common.StringPtr("assistant"),
// Content: common.StringPtr("Paris is known for its art, culture, and landmarks like the Eiffel Tower."),
// },
// },
// model: "",
// expectError: true,
// },
// {
// name: "EmptyMessages",
// messages: []*lkeap.Message{},
// model: "",
// expectError: true,
// },
// {
// name: "InvalidRole",
// messages: []*lkeap.Message{
// {
// Role: common.StringPtr("invalid-role"),
// Content: common.StringPtr("Test query"),
// },
// },
// model: "",
// expectError: true,
// },
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// // Initialize client for each test
// if err := client.Init(ctx); err != nil {
// t.Fatalf("Failed to initialize KnowledgeClient: %v", err)
// }
// // Perform query rewrite
// req := QueryRewriteRequest{
// Messages: tt.messages,
// Model: tt.model,
// }
// resp, err := client.QueryRewrite(ctx, req)
// // Check error expectation
// if tt.expectError {
// if err == nil {
// t.Error("Expected error, got none")
// } else {
// log.Debug().
// Str("method", "TestKnowledgeClient_QueryRewrite").
// Str("test_name", tt.name).
// Err(err).
// Msg("Received expected error")
// }
// return
// }
// // Check response
// if err != nil {
// t.Errorf("QueryRewrite failed: %v", err)
// }
// if resp.RewrittenQuery == "" {
// t.Error("Expected non-empty rewritten query")
// }
// log.Info().
// Str("method", "TestKnowledgeClient_QueryRewrite").
// Str("test_name", tt.name).
// Str("rewritten_query", resp.RewrittenQuery).
// Msg("Query rewrite successful")
// })
// }
// }
// func TestKnowledgeClient_QueryRewriteWithSummary(t *testing.T) {
// // Warning: Do not hardcode credentials in production code. Use environment variables or a secure vault.
// os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
// os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
// defer func() {
// os.Unsetenv("TENCENTCLOUD_SECRET_ID")
// os.Unsetenv("TENCENTCLOUD_SECRET_KEY")
// }()
// // Create client configuration
// config := ClientConfig{
// Endpoint: "lkeap.tencentcloudapi.com",
// Region: "ap-guangzhou",
// }
// // Initialize client
// client := NewKnowledgeClient(config)
// ctx := context.Background()
// // Test cases
// tests := []struct {
// name string
// userQuestion string
// assistantAnswer string
// historySummary string
// expectError bool
// }{
// {
// name: "ValidWithSummary",
// userQuestion: "你的家在哪里",
// assistantAnswer: "国内",
// historySummary: "User asked about location preferences earlier.",
// expectError: true, // Expect error due to potentially invalid credentials
// },
// {
// name: "ValidWithoutSummary",
// userQuestion: "你的家在哪里",
// assistantAnswer: "国内",
// historySummary: "",
// expectError: true,
// },
// {
// name: "EmptyQuestion",
// userQuestion: "",
// assistantAnswer: "国内",
// historySummary: "Summary",
// expectError: true,
// },
// {
// name: "EmptyAnswer",
// userQuestion: "你的家在哪里",
// assistantAnswer: "",
// historySummary: "Summary",
// expectError: true,
// },
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// // Initialize client for each test
// if err := client.Init(ctx); err != nil {
// t.Fatalf("Failed to initialize KnowledgeClient: %v", err)
// }
// // Perform query rewrite with summary
// resp, err := client.QueryRewriteWithSummary(ctx, tt.userQuestion, tt.assistantAnswer, tt.historySummary)
// // Check error expectation
// if tt.expectError {
// if err == nil {
// t.Error("Expected error, got none")
// } else {
// log.Debug().
// Str("method", "TestKnowledgeClient_QueryWithSummary").
// Str("test_name", tt.name).
// Str("error", err.Error()).
// Msg("Received expected error")
// }
// return
// }
// // Check response
// if err != nil {
// t.Errorf("QueryRewriteWithSummary failed: %v", err)
// }
// if resp.RewrittenQuery == "" {
// t.Error("Expected non-empty rewritten query")
// }
// log.Info().
// Str("method", "TestKnowledgeClient_QueryWithSummary").
// Str("test_name", tt.name).
// Str("rewritten_query", resp.RewrittenQuery).
// Msg("Query rewrite with summary successful")
// })
// }
// }
// Copyright 2025
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
package knowledge
import (
......@@ -296,221 +12,180 @@ import (
)
func TestMain(m *testing.M) {
// Configure zerolog for human-readable console output during tests
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
// Configure zerolog for human-readable console output during tests
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
// Run tests
os.Exit(m.Run())
// Run tests
os.Exit(m.Run())
}
func TestKnowledgeClient_QueryRewrite(t *testing.T) {
// Warning: Do not hardcode credentials in production code. Use environment variables or a secure vault.
// The credentials below are placeholders for testing purposes.
os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
defer func() {
os.Unsetenv("TENCENTCLOUD_SECRET_ID")
os.Unsetenv("TENCENTCLOUD_SECRET_KEY")
}()
// Create client configuration
config := ClientConfig{
Endpoint: "lkeap.tencentcloudapi.com",
Region: "ap-guangzhou",
}
// Initialize client
client := NewKnowledgeClient(config)
ctx := context.Background()
// Test cases
tests := []struct {
name string
messages []*lkeap.Message
model string
expectError bool
}{
{
name: "CurlPayload",
messages: []*lkeap.Message{
{
Role: common.StringPtr("user"),
Content: common.StringPtr("你的家在哪里"),
},
{
Role: common.StringPtr("assistant"),
Content: common.StringPtr("国内"),
},
{
Role: common.StringPtr("user"),
Content: common.StringPtr("国内哪里"),
},
},
model: "lke-query-rewrite-base",
expectError: true, // Expect error due to potentially invalid credentials
},
// {
// name: "ValidMultiTurnConversation",
// messages: []*lkeap.Message{
// {
// Role: common.StringPtr("user"),
// Content: common.StringPtr("What is the capital of France?"),
// },
// {
// Role: common.StringPtr("assistant"),
// Content: common.StringPtr("The capital of France is Paris."),
// },
// {
// Role: common.StringPtr("user"),
// Content: common.StringPtr("Tell me more about Paris."),
// },
// {
// Role: common.StringPtr("assistant"),
// Content: common.StringPtr("Paris is known for its art, culture, and landmarks like the Eiffel Tower."),
// },
// },
// model: "",
// expectError: true,
// },
// {
// name: "EmptyMessages",
// messages: []*lkeap.Message{},
// model: "",
// expectError: true,
// },
// {
// name: "InvalidRole",
// messages: []*lkeap.Message{
// {
// Role: common.StringPtr("invalid-role"),
// Content: common.StringPtr("Test query"),
// },
// },
// model: "",
// expectError: true,
// },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Initialize client for each test
if err := client.Init(ctx); err != nil {
t.Fatalf("Failed to initialize KnowledgeClient: %v", err)
}
// Perform query rewrite
req := QueryRewriteRequest{
Messages: tt.messages,
Model: tt.model,
}
resp, err := client.QueryRewrite(ctx, req)
// Check error expectation
if tt.expectError {
if err == nil {
t.Error("Expected error, got none")
} else {
log.Debug().
Str("method", "TestKnowledgeClient_QueryRewrite").
Str("test_name", tt.name).
Err(err).
Msg("Received expected error")
}
return
}
// Check response (only for non-error cases)
if err != nil {
t.Fatalf("QueryRewrite failed: %v", err)
}
if resp.RewrittenQuery == "" {
t.Error("Expected non-empty rewritten query")
}
log.Info().
Str("method", "TestKnowledgeClient_QueryRewrite").
Str("test_name", tt.name).
Str("rewritten_query", resp.RewrittenQuery).
Msg("Query rewrite successful")
})
}
// Warning: Do not hardcode credentials in production code. Use environment variables or a secure vault.
// The credentials below are placeholders for testing purposes.
os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
defer func() {
os.Unsetenv("TENCENTCLOUD_SECRET_ID")
os.Unsetenv("TENCENTCLOUD_SECRET_KEY")
}()
// Create client configuration
config := ClientConfig{
Endpoint: "lkeap.tencentcloudapi.com",
Region: "ap-guangzhou",
}
// Initialize client
client := NewKnowledgeClient(config)
ctx := context.Background()
// Test cases
tests := []struct {
name string
messages []*lkeap.Message
model string
expectError bool
}{
{
name: "CurlPayload",
messages: []*lkeap.Message{
{
Role: common.StringPtr("user"),
Content: common.StringPtr("你的家在哪里"),
},
{
Role: common.StringPtr("assistant"),
Content: common.StringPtr("国内"),
},
{
Role: common.StringPtr("user"),
Content: common.StringPtr("国内哪里"),
},
},
model: "lke-query-rewrite-base",
expectError: true, // Expect error due to potentially invalid credentials
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Initialize client for each test
if err := client.Init(ctx); err != nil {
t.Fatalf("Failed to initialize KnowledgeClient: %v", err)
}
// Perform query rewrite
req := QueryRewriteRequest{
Messages: tt.messages,
Model: tt.model,
}
resp, err := client.QueryRewrite(ctx, req)
// Check error expectation
if tt.expectError {
if err == nil {
t.Error("Expected error, got none")
} else {
log.Debug().
Str("method", "TestKnowledgeClient_QueryRewrite").
Str("test_name", tt.name).
Err(err).
Msg("Received expected error")
}
return
}
// Check response (only for non-error cases)
if err != nil {
t.Fatalf("QueryRewrite failed: %v", err)
}
if resp.RewrittenQuery == "" {
t.Error("Expected non-empty rewritten query")
}
log.Info().
Str("method", "TestKnowledgeClient_QueryRewrite").
Str("test_name", tt.name).
Str("rewritten_query", resp.RewrittenQuery).
Msg("Query rewrite successful")
})
}
}
func TestKnowledgeClient_QueryRewriteWithSummary(t *testing.T) {
// Warning: Do not hardcode credentials in production code. Use environment variables or a secure vault.
os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
defer func() {
os.Unsetenv("TENCENTCLOUD_SECRET_ID")
os.Unsetenv("TENCENTCLOUD_SECRET_KEY")
}()
// Create client configuration
config := ClientConfig{
Endpoint: "lkeap.tencentcloudapi.com",
Region: "ap-guangzhou",
}
// Initialize client
client := NewKnowledgeClient(config)
ctx := context.Background()
// Test cases
tests := []struct {
name string
userQuestion string
assistantAnswer string
historySummary string
expectError bool
}{
{
name: "ValidWithSummary",
userQuestion: "你的家在哪里",
assistantAnswer: "国内",
historySummary: "User asked about location preferences earlier.",
expectError: true, // Expect error due to potentially invalid credentials
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Initialize client for each test
if err := client.Init(ctx); err != nil {
t.Fatalf("Failed to initialize KnowledgeClient: %v", err)
}
// Perform query rewrite with summary
resp, err := client.QueryRewriteWithSummary(ctx, tt.userQuestion, tt.assistantAnswer, tt.historySummary)
// Check error expectation
if tt.expectError {
if err == nil {
t.Error("Expected error, got none")
} else {
log.Debug().
Str("method", "TestKnowledgeClient_QueryWithSummary").
Str("test_name", tt.name).
Str("error", err.Error()).
Msg("Received expected error")
}
return
}
// Check response
if err != nil {
t.Errorf("QueryRewriteWithSummary failed: %v", err)
}
if resp.RewrittenQuery == "" {
t.Error("Expected non-empty rewritten query")
}
log.Info().
Str("method", "TestKnowledgeClient_QueryWithSummary").
Str("test_name", tt.name).
Str("rewritten_query", resp.RewrittenQuery).
Msg("Query rewrite with summary successful")
})
}
}
\ No newline at end of file
// Warning: Do not hardcode credentials in production code. Use environment variables or a secure vault.
os.Setenv("TENCENTCLOUD_SECRET_ID", "AKID64oLfmfLtESUJ6i8LPSM4gCVbiniQuBF")
os.Setenv("TENCENTCLOUD_SECRET_KEY", "rX2JMBnBMJ2YqulOo37xa5OUMSN4Xnpd")
defer func() {
os.Unsetenv("TENCENTCLOUD_SECRET_ID")
os.Unsetenv("TENCENTCLOUD_SECRET_KEY")
}()
// Create client configuration
config := ClientConfig{
Endpoint: "lkeap.tencentcloudapi.com",
Region: "ap-guangzhou",
}
// Initialize client
client := NewKnowledgeClient(config)
ctx := context.Background()
// Test cases
tests := []struct {
name string
userQuestion string
assistantAnswer string
historySummary string
expectError bool
}{
{
name: "ValidWithSummary",
userQuestion: "你的家在哪里",
assistantAnswer: "国内",
historySummary: "null", //"User asked about location preferences earlier.",
expectError: true, // Expect error due to potentially invalid credentials
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Initialize client for each test
if err := client.Init(ctx); err != nil {
t.Fatalf("Failed to initialize KnowledgeClient: %v", err)
}
// Perform query rewrite with summary
resp, err := client.QueryRewriteWithSummary(ctx, tt.userQuestion, tt.assistantAnswer, tt.historySummary)
// Check error expectation
if tt.expectError {
if err == nil {
t.Error("Expected error, got none")
} else {
log.Debug().
Str("method", "TestKnowledgeClient_QueryWithSummary").
Str("test_name", tt.name).
Str("error", err.Error()).
Msg("Received expected error")
}
return
}
// Check response
if err != nil {
t.Errorf("QueryRewriteWithSummary failed: %v", err)
}
if resp.RewrittenQuery == "" {
t.Error("Expected non-empty rewritten query")
}
log.Info().
Str("method", "TestKnowledgeClient_QueryWithSummary").
Str("test_name", tt.name).
Str("rewritten_query", resp.RewrittenQuery).
Msg("Query rewrite with summary successful")
})
}
}
......@@ -39,640 +39,611 @@ const provider = "milvus"
// Field names for Milvus schema.
const (
idField = "id"
vectorField = "vector"
textField = "text"
metadataField = "metadata"
idField = "id"
vectorField = "vector"
textField = "text"
metadataField = "metadata"
)
// Milvus holds configuration for the plugin.
type Milvus struct {
// Milvus server address (host:port, e.g., "localhost:19530").
// Defaults to MILVUS_ADDRESS environment variable.
Addr string
// Username for authentication.
// Defaults to MILVUS_USERNAME.
Username string
// Password for authentication.
// Defaults to MILVUS_PASSWORD.
Password string
// Token for authentication (alternative to username/password).
// Defaults to MILVUS_TOKEN.
Token string
client client.Client // Milvus client.
mu sync.Mutex // Mutex to control access.
initted bool // Whether the plugin has been initialized.
// Milvus server address (host:port, e.g., "localhost:19530").
// Defaults to MILVUS_ADDRESS environment variable.
Addr string
// Username for authentication.
// Defaults to MILVUS_USERNAME.
Username string
// Password for authentication.
// Defaults to MILVUS_PASSWORD.
Password string
// Token for authentication (alternative to username/password).
// Defaults to MILVUS_TOKEN.
Token string
client client.Client // Milvus client.
mu sync.Mutex // Mutex to control access.
initted bool // Whether the plugin has been initialized.
}
// Name returns the plugin name.
func (m *Milvus) Name() string {
return provider
return provider
}
// Init initializes the Milvus plugin.
func (m *Milvus) Init(ctx context.Context, g *genkit.Genkit) (err error) {
log.Info().Str("method", "Milvus.Init").Msg("Initializing Milvus plugin")
if m == nil {
m = &Milvus{}
}
m.mu.Lock()
defer m.mu.Unlock()
defer func() {
if err != nil {
log.Error().Err(err).Str("method", "Milvus.Init").Msg("Initialization failed")
err = fmt.Errorf("milvus.Init: %w", err)
} else {
log.Info().Str("method", "Milvus.Init").Msg("Initialization successful")
}
}()
if m.initted {
return errors.New("plugin already initialized")
}
// Load configuration.
addr := m.Addr
if addr == "" {
addr = os.Getenv("MILVUS_ADDRESS")
}
if addr == "" {
return errors.New("milvus address required")
}
username := m.Username
if username == "" {
username = os.Getenv("MILVUS_USERNAME")
}
password := m.Password
if password == "" {
password = os.Getenv("MILVUS_PASSWORD")
}
token := m.Token
if token == "" {
token = os.Getenv("MILVUS_TOKEN")
}
// Initialize Milvus client.
config := client.Config{
Address: addr,
Username: username,
Password: password,
APIKey: token,
}
client, err := client.NewClient(ctx, config)
if err != nil {
return fmt.Errorf("failed to initialize Milvus client: %v", err)
}
m.client = client
m.initted = true
return nil
log.Info().Str("method", "Milvus.Init").Msg("Initializing Milvus plugin")
if m == nil {
m = &Milvus{}
}
m.mu.Lock()
defer m.mu.Unlock()
defer func() {
if err != nil {
log.Error().Err(err).Str("method", "Milvus.Init").Msg("Initialization failed")
err = fmt.Errorf("milvus.Init: %w", err)
} else {
log.Info().Str("method", "Milvus.Init").Msg("Initialization successful")
}
}()
if m.initted {
return errors.New("plugin already initialized")
}
// Load configuration.
addr := m.Addr
if addr == "" {
addr = os.Getenv("MILVUS_ADDRESS")
}
if addr == "" {
return errors.New("milvus address required")
}
username := m.Username
if username == "" {
username = os.Getenv("MILVUS_USERNAME")
}
password := m.Password
if password == "" {
password = os.Getenv("MILVUS_PASSWORD")
}
token := m.Token
if token == "" {
token = os.Getenv("MILVUS_TOKEN")
}
// Initialize Milvus client.
config := client.Config{
Address: addr,
Username: username,
Password: password,
APIKey: token,
}
client, err := client.NewClient(ctx, config)
if err != nil {
return fmt.Errorf("failed to initialize Milvus client: %v", err)
}
m.client = client
m.initted = true
return nil
}
// CollectionConfig holds configuration for an indexer/retriever pair.
type CollectionConfig struct {
// Milvus collection name. Must not be empty.
Collection string
// Embedding vector dimension (e.g., 1536 for text-embedding-ada-002).
Dimension int
// Embedder for generating vectors.
Embedder ai.Embedder
// Embedder options.
EmbedderOptions any
// Milvus collection name. Must not be empty.
Collection string
// Embedding vector dimension (e.g., 1536 for text-embedding-ada-002).
Dimension int
// Embedder for generating vectors.
Embedder ai.Embedder
// Embedder options.
EmbedderOptions any
}
// DefineIndexerAndRetriever defines an Indexer and Retriever for a Milvus collection.
func DefineIndexerAndRetriever(ctx context.Context, g *genkit.Genkit, cfg CollectionConfig) (ai.Indexer, ai.Retriever, error) {
log.Info().
Str("method", "DefineIndexerAndRetriever").
Str("collection", cfg.Collection).
Int("dimension", cfg.Dimension).
Msg("Defining indexer and retriever")
if cfg.Embedder == nil {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("Embedder required")
return nil, nil, errors.New("milvus: Embedder required")
}
if cfg.Collection == "" {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("Collection name required")
return nil, nil, errors.New("milvus: collection name required")
}
if cfg.Dimension <= 0 {
log.Error().Str("method", "DefineIndexerAndRetriever").Int("dimension", cfg.Dimension).Msg("Dimension must be positive")
return nil, nil, errors.New("milvus: dimension must be positive")
}
m := genkit.LookupPlugin(g, provider)
if m == nil {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("Milvus plugin not found")
return nil, nil, errors.New("milvus plugin not found; did you call genkit.Init with the milvus plugin?")
}
milvus := m.(*Milvus)
ds, err := milvus.newDocStore(ctx, &cfg)
if err != nil {
log.Error().Err(err).Str("method", "DefineIndexerAndRetriever").Str("collection", cfg.Collection).Msg("Failed to create doc store")
return nil, nil, err
}
indexer := genkit.DefineIndexer(g, provider, cfg.Collection, ds.Index)
retriever := genkit.DefineRetriever(g, provider, cfg.Collection, ds.Retrieve)
log.Info().Str("method", "DefineIndexerAndRetriever").Str("collection", cfg.Collection).Msg("Indexer and retriever defined successfully")
return indexer, retriever, nil
log.Info().
Str("method", "DefineIndexerAndRetriever").
Str("collection", cfg.Collection).
Int("dimension", cfg.Dimension).
Msg("Defining indexer and retriever")
if cfg.Embedder == nil {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("Embedder required")
return nil, nil, errors.New("milvus: Embedder required")
}
if cfg.Collection == "" {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("Collection name required")
return nil, nil, errors.New("milvus: collection name required")
}
if cfg.Dimension <= 0 {
log.Error().Str("method", "DefineIndexerAndRetriever").Int("dimension", cfg.Dimension).Msg("Dimension must be positive")
return nil, nil, errors.New("milvus: dimension must be positive")
}
m := genkit.LookupPlugin(g, provider)
if m == nil {
log.Error().Str("method", "DefineIndexerAndRetriever").Msg("Milvus plugin not found")
return nil, nil, errors.New("milvus plugin not found; did you call genkit.Init with the milvus plugin?")
}
milvus := m.(*Milvus)
ds, err := milvus.newDocStore(ctx, &cfg)
if err != nil {
log.Error().Err(err).Str("method", "DefineIndexerAndRetriever").Str("collection", cfg.Collection).Msg("Failed to create doc store")
return nil, nil, err
}
indexer := genkit.DefineIndexer(g, provider, cfg.Collection, ds.Index)
retriever := genkit.DefineRetriever(g, provider, cfg.Collection, ds.Retrieve)
log.Info().Str("method", "DefineIndexerAndRetriever").Str("collection", cfg.Collection).Msg("Indexer and retriever defined successfully")
return indexer, retriever, nil
}
// docStore defines an Indexer and a Retriever.
type docStore struct {
client client.Client
collection string
dimension int
embedder ai.Embedder
embedderOptions map[string]interface{}
client client.Client
collection string
dimension int
embedder ai.Embedder
embedderOptions map[string]interface{}
}
// newDocStore creates a docStore.
func (m *Milvus) newDocStore(ctx context.Context, cfg *CollectionConfig) (*docStore, error) {
log.Info().
Str("method", "Milvus.newDocStore").
Str("collection", cfg.Collection).
Int("dimension", cfg.Dimension).
Msg("Creating new doc store")
if m.client == nil {
log.Error().Str("method", "Milvus.newDocStore").Msg("Milvus client not initialized")
return nil, errors.New("milvus.Init not called")
}
// Check/create collection.
exists, err := m.client.HasCollection(ctx, cfg.Collection)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to check collection")
return nil, fmt.Errorf("failed to check collection %q: %v", cfg.Collection, err)
}
if !exists {
// Define schema with textField as primary key, plus user_id and username fields.
schema := &entity.Schema{
CollectionName: cfg.Collection,
Fields: []*entity.Field{
{
Name: vectorField,
DataType: entity.FieldTypeFloatVector,
TypeParams: map[string]string{
"dim": fmt.Sprintf("%d", cfg.Dimension),
},
},
{
Name: textField,
DataType: entity.FieldTypeVarChar,
PrimaryKey: true,
TypeParams: map[string]string{
"max_length": "65535",
},
},
{
Name: metadataField,
DataType: entity.FieldTypeJSON,
},
{
Name: "user_id",
DataType: entity.FieldTypeVarChar,
TypeParams: map[string]string{
"max_length": "128",
},
},
{
Name: "username",
DataType: entity.FieldTypeVarChar,
TypeParams: map[string]string{
"max_length": "128",
},
},
},
}
err = m.client.CreateCollection(ctx, schema, entity.DefaultShardNumber)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to create collection")
return nil, fmt.Errorf("failed to create collection %q: %v", cfg.Collection, err)
}
// Create HNSW index for vectorField.
index, err := entity.NewIndexHNSW(
entity.L2,
8, // M
96, // efConstruction
)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to create HNSW index")
return nil, fmt.Errorf("entity.NewIndexHNSW: %v", err)
}
err = m.client.CreateIndex(ctx, cfg.Collection, vectorField, index, false)
if err != nil {
log.Error().Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msgf("Failed to create index: %s",err.Error())
return nil, fmt.Errorf("failed to create index: %v", err)
}
}
// Load collection.
err = m.client.LoadCollection(ctx, cfg.Collection, false)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to load collection")
return nil, fmt.Errorf("failed to load collection %q: %v", cfg.Collection, err)
}
// Convert EmbedderOptions to map[string]interface{}.
var embedderOptions map[string]interface{}
if cfg.EmbedderOptions != nil {
opts, ok := cfg.EmbedderOptions.(map[string]interface{})
if !ok {
log.Error().
Str("method", "Milvus.newDocStore").
Str("type", fmt.Sprintf("%T", cfg.EmbedderOptions)).
Msg("EmbedderOptions must be a map[string]interface{}")
return nil, fmt.Errorf("EmbedderOptions must be a map[string]interface{}, got %T", cfg.EmbedderOptions)
}
embedderOptions = opts
} else {
embedderOptions = make(map[string]interface{})
}
log.Info().Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Doc store created successfully")
return &docStore{
client: m.client,
collection: cfg.Collection,
dimension: cfg.Dimension,
embedder: cfg.Embedder,
embedderOptions: embedderOptions,
}, nil
log.Info().
Str("method", "Milvus.newDocStore").
Str("collection", cfg.Collection).
Int("dimension", cfg.Dimension).
Msg("Creating new doc store")
if m.client == nil {
log.Error().Str("method", "Milvus.newDocStore").Msg("Milvus client not initialized")
return nil, errors.New("milvus.Init not called")
}
// Check/create collection.
exists, err := m.client.HasCollection(ctx, cfg.Collection)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to check collection")
return nil, fmt.Errorf("failed to check collection %q: %v", cfg.Collection, err)
}
if !exists {
// Define schema with textField as primary key, plus user_id and username fields.
schema := &entity.Schema{
CollectionName: cfg.Collection,
Fields: []*entity.Field{
{
Name: vectorField,
DataType: entity.FieldTypeFloatVector,
TypeParams: map[string]string{
"dim": fmt.Sprintf("%d", cfg.Dimension),
},
},
{
Name: textField,
DataType: entity.FieldTypeVarChar,
PrimaryKey: true,
TypeParams: map[string]string{
"max_length": "65535",
},
},
{
Name: metadataField,
DataType: entity.FieldTypeJSON,
},
{
Name: "user_id",
DataType: entity.FieldTypeVarChar,
TypeParams: map[string]string{
"max_length": "128",
},
},
{
Name: "username",
DataType: entity.FieldTypeVarChar,
TypeParams: map[string]string{
"max_length": "128",
},
},
},
}
err = m.client.CreateCollection(ctx, schema, entity.DefaultShardNumber)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to create collection")
return nil, fmt.Errorf("failed to create collection %q: %v", cfg.Collection, err)
}
// Create HNSW index for vectorField.
index, err := entity.NewIndexHNSW(
entity.L2,
8, // M
96, // efConstruction
)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to create HNSW index")
return nil, fmt.Errorf("entity.NewIndexHNSW: %v", err)
}
err = m.client.CreateIndex(ctx, cfg.Collection, vectorField, index, false)
if err != nil {
log.Error().Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msgf("Failed to create index: %s", err.Error())
return nil, fmt.Errorf("failed to create index: %v", err)
}
}
// Load collection.
err = m.client.LoadCollection(ctx, cfg.Collection, false)
if err != nil {
log.Error().Err(err).Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Failed to load collection")
return nil, fmt.Errorf("failed to load collection %q: %v", cfg.Collection, err)
}
// Convert EmbedderOptions to map[string]interface{}.
var embedderOptions map[string]interface{}
if cfg.EmbedderOptions != nil {
opts, ok := cfg.EmbedderOptions.(map[string]interface{})
if !ok {
log.Error().
Str("method", "Milvus.newDocStore").
Str("type", fmt.Sprintf("%T", cfg.EmbedderOptions)).
Msg("EmbedderOptions must be a map[string]interface{}")
return nil, fmt.Errorf("EmbedderOptions must be a map[string]interface{}, got %T", cfg.EmbedderOptions)
}
embedderOptions = opts
} else {
embedderOptions = make(map[string]interface{})
}
log.Info().Str("method", "Milvus.newDocStore").Str("collection", cfg.Collection).Msg("Doc store created successfully")
return &docStore{
client: m.client,
collection: cfg.Collection,
dimension: cfg.Dimension,
embedder: cfg.Embedder,
embedderOptions: embedderOptions,
}, nil
}
// Indexer returns the indexer for a collection.
func Indexer(g *genkit.Genkit, collection string) ai.Indexer {
log.Info().Str("method", "Indexer").Str("collection", collection).Msg("Looking up indexer")
indexer := genkit.LookupIndexer(g, provider, collection)
if indexer == nil {
log.Warn().Str("method", "Indexer").Str("collection", collection).Msg("Indexer not found")
}
return indexer
log.Info().Str("method", "Indexer").Str("collection", collection).Msg("Looking up indexer")
indexer := genkit.LookupIndexer(g, provider, collection)
if indexer == nil {
log.Warn().Str("method", "Indexer").Str("collection", collection).Msg("Indexer not found")
}
return indexer
}
// Retriever returns the retriever for a collection.
func Retriever(g *genkit.Genkit, collection string) ai.Retriever {
log.Info().Str("method", "Retriever").Str("collection", collection).Msg("Looking up retriever")
retriever := genkit.LookupRetriever(g, provider, collection)
if retriever == nil {
log.Warn().Str("method", "Retriever").Str("collection", collection).Msg("Retriever not found")
}
return retriever
log.Info().Str("method", "Retriever").Str("collection", collection).Msg("Looking up retriever")
retriever := genkit.LookupRetriever(g, provider, collection)
if retriever == nil {
log.Warn().Str("method", "Retriever").Str("collection", collection).Msg("Retriever not found")
}
return retriever
}
// Index implements the Indexer.Index method.
func (ds *docStore) Index(ctx context.Context, req *ai.IndexerRequest) error {
log.Info().
Str("method", "docStore.Index").
Str("collection", ds.collection).
Int("documents", len(req.Documents)).
Msg("Starting index operation")
if len(req.Documents) == 0 {
log.Debug().Str("method", "docStore.Index").Str("collection", ds.collection).Msg("No documents to index")
return nil
}
// Embed documents.
ereq := &ai.EmbedRequest{
Input: req.Documents,
Options: ds.embedderOptions,
}
eres, err := ds.embedder.Embed(ctx, ereq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Index").Str("collection", ds.collection).Msg("Embedding failed")
return fmt.Errorf("milvus index embedding failed: %w", err)
}
// Validate embedding count matches document count.
if len(eres.Embeddings) != len(req.Documents) {
log.Error().
Str("method", "docStore.Index").
Str("collection", ds.collection).
Int("embeddings", len(eres.Embeddings)).
Int("documents", len(req.Documents)).
Msg("Mismatch in embedding and document count")
return fmt.Errorf("mismatch: got %d embeddings for %d documents", len(eres.Embeddings), len(req.Documents))
}
// Prepare row-based data.
var rows []interface{}
for i, emb := range eres.Embeddings {
doc := req.Documents[i]
if doc.Metadata == nil {
log.Error().Str("method", "docStore.Index").Int("index", i).Msg("Document metadata is nil")
return fmt.Errorf("req.Query.Metadata must be not nil, got type %T", doc.Metadata)
}
// Extract username and user_id from req.Query.Metadata
userName, ok := doc.Metadata[util.UserNameKey].(string)
if !ok {
log.Error().Str("method", "docStore.Index").Int("index", i).Msg("Missing username in metadata")
return fmt.Errorf("req.Query.Metadata must provide username key")
}
userId, ok := doc.Metadata[util.UserIdKey].(string)
if !ok {
log.Error().Str("method", "docStore.Index").Int("index", i).Msg("Missing user_id in metadata")
return fmt.Errorf("req.Query.Metadata must provide user_id key")
}
var sb strings.Builder
for _, p := range doc.Content {
if p.IsText() {
sb.WriteString(p.Text)
}
}
text := sb.String()
metadata := doc.Metadata
if metadata == nil {
metadata = make(map[string]interface{})
}
// Create row with explicit metadata field.
row := make(map[string]interface{})
row["vector"] = emb.Embedding
row["text"] = text
row["user_id"] = userId
row["username"] = userName
row["metadata"] = metadata
rows = append(rows, row)
log.Debug().
Str("method", "docStore.Index").
Int("index", i).
Str("collection", ds.collection).
Int("vector_length", len(emb.Embedding)).
Str("text", text).
Str("user_id", userId).
Str("username", userName).
Interface("metadata", metadata).
Msg("Prepared row for insertion")
}
log.Info().
Str("method", "docStore.Index").
Str("collection", ds.collection).
Int("rows", len(rows)).
Msg("Inserting rows into Milvus")
// Insert rows into Milvus.
_, err = ds.client.InsertRows(ctx, ds.collection, "", rows)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Index").Str("collection", ds.collection).Msg("Failed to insert rows")
return fmt.Errorf("milvus insert rows failed: %w", err)
}
log.Info().Str("method", "docStore.Index").Str("collection", ds.collection).Int("rows", len(rows)).Msg("Index operation completed successfully")
return nil
log.Info().
Str("method", "docStore.Index").
Str("collection", ds.collection).
Int("documents", len(req.Documents)).
Msg("Starting index operation")
if len(req.Documents) == 0 {
log.Debug().Str("method", "docStore.Index").Str("collection", ds.collection).Msg("No documents to index")
return nil
}
// Embed documents.
ereq := &ai.EmbedRequest{
Input: req.Documents,
Options: ds.embedderOptions,
}
eres, err := ds.embedder.Embed(ctx, ereq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Index").Str("collection", ds.collection).Msg("Embedding failed")
return fmt.Errorf("milvus index embedding failed: %w", err)
}
// Validate embedding count matches document count.
if len(eres.Embeddings) != len(req.Documents) {
log.Error().
Str("method", "docStore.Index").
Str("collection", ds.collection).
Int("embeddings", len(eres.Embeddings)).
Int("documents", len(req.Documents)).
Msg("Mismatch in embedding and document count")
return fmt.Errorf("mismatch: got %d embeddings for %d documents", len(eres.Embeddings), len(req.Documents))
}
// Prepare row-based data.
var rows []interface{}
for i, emb := range eres.Embeddings {
doc := req.Documents[i]
if doc.Metadata == nil {
log.Error().Str("method", "docStore.Index").Int("index", i).Msg("Document metadata is nil")
return fmt.Errorf("req.Query.Metadata must be not nil, got type %T", doc.Metadata)
}
// Extract username and user_id from req.Query.Metadata
userName, ok := doc.Metadata[util.UserNameKey].(string)
if !ok {
log.Error().Str("method", "docStore.Index").Int("index", i).Msg("Missing username in metadata")
return fmt.Errorf("req.Query.Metadata must provide username key")
}
userId, ok := doc.Metadata[util.UserIdKey].(string)
if !ok {
log.Error().Str("method", "docStore.Index").Int("index", i).Msg("Missing user_id in metadata")
return fmt.Errorf("req.Query.Metadata must provide user_id key")
}
var sb strings.Builder
for _, p := range doc.Content {
if p.IsText() {
sb.WriteString(p.Text)
}
}
text := sb.String()
metadata := doc.Metadata
if metadata == nil {
metadata = make(map[string]interface{})
}
// Create row with explicit metadata field.
row := make(map[string]interface{})
row["vector"] = emb.Embedding
row["text"] = text
row["user_id"] = userId
row["username"] = userName
row["metadata"] = metadata
rows = append(rows, row)
log.Debug().
Str("method", "docStore.Index").
Int("index", i).
Str("collection", ds.collection).
Int("vector_length", len(emb.Embedding)).
Str("text", text).
Str("user_id", userId).
Str("username", userName).
Interface("metadata", metadata).
Msg("Prepared row for insertion")
}
log.Info().
Str("method", "docStore.Index").
Str("collection", ds.collection).
Int("rows", len(rows)).
Msg("Inserting rows into Milvus")
// Insert rows into Milvus.
_, err = ds.client.InsertRows(ctx, ds.collection, "", rows)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Index").Str("collection", ds.collection).Msg("Failed to insert rows")
return fmt.Errorf("milvus insert rows failed: %w", err)
}
log.Info().Str("method", "docStore.Index").Str("collection", ds.collection).Int("rows", len(rows)).Msg("Index operation completed successfully")
return nil
}
// RetrieverOptions for Milvus retrieval.
type RetrieverOptions struct {
Count int `json:"count,omitempty"` // Max documents to retrieve.
MetricType string `json:"metric_type,omitempty"` // Similarity metric (e.g., "L2", "IP").
Count int `json:"count,omitempty"` // Max documents to retrieve.
MetricType string `json:"metric_type,omitempty"` // Similarity metric (e.g., "L2", "IP").
}
// Retrieve implements the Retriever.Retrieve method.
func (ds *docStore) Retrieve(ctx context.Context, req *ai.RetrieverRequest) (*ai.RetrieverResponse, error) {
log.Info().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Msg("Starting retrieve operation")
if req.Query.Metadata == nil {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Query metadata is nil")
return nil, fmt.Errorf("req.Query.Metadata must be not nil, got type %T", req.Query.Metadata)
}
// Extract username and user_id from req.Query.Metadata
userName, ok := req.Query.Metadata[util.UserNameKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Missing username in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide username key")
}
userId, ok := req.Query.Metadata[util.UserIdKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Missing user_id in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide user_id key")
}
count := 3 // Default.
metricTypeStr := "L2"
if req.Options != nil {
ropt, ok := req.Options.(*RetrieverOptions)
if !ok {
log.Error().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Str("options_type", fmt.Sprintf("%T", req.Options)).
Msg("Invalid options type")
return nil, fmt.Errorf("milvus.Retrieve options have type %T, want %T", req.Options, &RetrieverOptions{})
}
if ropt.Count > 0 {
count = ropt.Count
}
if ropt.MetricType != "" {
metricTypeStr = ropt.MetricType
}
}
// Map string metric type to entity.MetricType.
var metricType entity.MetricType
switch metricTypeStr {
case "L2":
metricType = entity.L2
case "IP":
metricType = entity.IP
default:
log.Error().Str("method", "docStore.Retrieve").Str("metric_type", metricTypeStr).Msg("Unsupported metric type")
return nil, fmt.Errorf("unsupported metric type: %s", metricTypeStr)
}
// Embed query.
ereq := &ai.EmbedRequest{
Input: []*ai.Document{req.Query},
Options: ds.embedderOptions,
}
eres, err := ds.embedder.Embed(ctx, ereq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Embedding failed")
return nil, fmt.Errorf("milvus retrieve embedding failed: %v", err)
}
if len(eres.Embeddings) == 0 {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("No embeddings generated")
return nil, errors.New("no embeddings generated for query")
}
queryVector := entity.FloatVector(eres.Embeddings[0].Embedding)
// Create search parameters.
searchParams, err := entity.NewIndexHNSWSearchParam(64) // ef
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Failed to create HNSW search parameters")
return nil, fmt.Errorf("NewIndexHNSWSearchParam failed: %v", err)
}
// Define filter expression for user_id
expr := fmt.Sprintf("user_id == %q", userId)
log.Debug().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Str("user_id", userId).
Str("metric_type", metricTypeStr).
Int("count", count).
Msg("Performing vector search")
// Perform vector search to get IDs, text, and metadata.
results, err := ds.client.Search(
ctx,
ds.collection,
[]string{},
expr,
[]string{textField, metadataField},
[]entity.Vector{queryVector},
vectorField,
metricType,
count,
searchParams,
)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Search failed")
return nil, fmt.Errorf("milvus search failed: %v", err)
}
// Process search results.
var docs []*ai.Document
for _, result := range results {
// Find text and metadata columns in search results.
var textCol, metaCol entity.Column
for _, col := range result.Fields {
if col.Name() == textField {
textCol = col
}
if col.Name() == metadataField {
metaCol = col
}
}
// Ensure text column exists.
if textCol == nil {
log.Error().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Str("field", textField).
Msg("Text column not found in search results")
return nil, fmt.Errorf("text column %s not found in search results", textField)
}
// Iterate over rows.
for i := 0; i < result.ResultCount; i++ {
// Get text value.
text, err := textCol.GetAsString(i)
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Msg("Failed to parse text")
continue
}
// Get metadata value (optional).
var metadata map[string]interface{}
if metaCol != nil {
metaStr, err := metaCol.GetAsString(i)
if err == nil && metaStr != "" {
if err := json.Unmarshal([]byte(metaStr), &metadata); err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Msg("Failed to parse metadata")
continue
}
} else if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Msg("Failed to get metadata string")
}
}
// Ensure metadata includes user_id and username from query.
if metadata == nil {
metadata = make(map[string]interface{})
}
metadata[util.UserIdKey] = userId
metadata[util.UserNameKey] = userName
// Create document.
doc := ai.DocumentFromText(text, metadata)
docs = append(docs, doc)
log.Debug().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Str("text", text).
Interface("metadata", metadata).
Msg("Processed search result")
}
}
log.Info().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("documents", len(docs)).
Msg("Retrieve operation completed successfully")
return &ai.RetrieverResponse{
Documents: docs,
}, nil
log.Info().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Msg("Starting retrieve operation")
if req.Query.Metadata == nil {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Query metadata is nil")
return nil, fmt.Errorf("req.Query.Metadata must be not nil, got type %T", req.Query.Metadata)
}
// Extract username and user_id from req.Query.Metadata
userName, ok := req.Query.Metadata[util.UserNameKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Missing username in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide username key")
}
userId, ok := req.Query.Metadata[util.UserIdKey].(string)
if !ok {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Missing user_id in metadata")
return nil, fmt.Errorf("req.Query.Metadata must provide user_id key")
}
count := 3 // Default.
metricTypeStr := "L2"
if req.Options != nil {
ropt, ok := req.Options.(*RetrieverOptions)
if !ok {
log.Error().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Str("options_type", fmt.Sprintf("%T", req.Options)).
Msg("Invalid options type")
return nil, fmt.Errorf("milvus.Retrieve options have type %T, want %T", req.Options, &RetrieverOptions{})
}
if ropt.Count > 0 {
count = ropt.Count
}
if ropt.MetricType != "" {
metricTypeStr = ropt.MetricType
}
}
// Map string metric type to entity.MetricType.
var metricType entity.MetricType
switch metricTypeStr {
case "L2":
metricType = entity.L2
case "IP":
metricType = entity.IP
default:
log.Error().Str("method", "docStore.Retrieve").Str("metric_type", metricTypeStr).Msg("Unsupported metric type")
return nil, fmt.Errorf("unsupported metric type: %s", metricTypeStr)
}
// Embed query.
ereq := &ai.EmbedRequest{
Input: []*ai.Document{req.Query},
Options: ds.embedderOptions,
}
eres, err := ds.embedder.Embed(ctx, ereq)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Embedding failed")
return nil, fmt.Errorf("milvus retrieve embedding failed: %v", err)
}
if len(eres.Embeddings) == 0 {
log.Error().Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("No embeddings generated")
return nil, errors.New("no embeddings generated for query")
}
queryVector := entity.FloatVector(eres.Embeddings[0].Embedding)
// Create search parameters.
searchParams, err := entity.NewIndexHNSWSearchParam(64) // ef
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Failed to create HNSW search parameters")
return nil, fmt.Errorf("NewIndexHNSWSearchParam failed: %v", err)
}
// Define filter expression for user_id
expr := fmt.Sprintf("user_id == %q", userId)
log.Debug().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Str("user_id", userId).
Str("metric_type", metricTypeStr).
Int("count", count).
Msg("Performing vector search")
// Perform vector search to get IDs, text, and metadata.
results, err := ds.client.Search(
ctx,
ds.collection,
[]string{},
expr,
[]string{textField, metadataField},
[]entity.Vector{queryVector},
vectorField,
metricType,
count,
searchParams,
)
if err != nil {
log.Error().Err(err).Str("method", "docStore.Retrieve").Str("collection", ds.collection).Msg("Search failed")
return nil, fmt.Errorf("milvus search failed: %v", err)
}
// Process search results.
var docs []*ai.Document
for _, result := range results {
// Find text and metadata columns in search results.
var textCol, metaCol entity.Column
for _, col := range result.Fields {
if col.Name() == textField {
textCol = col
}
if col.Name() == metadataField {
metaCol = col
}
}
// Ensure text column exists.
if textCol == nil {
log.Error().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Str("field", textField).
Msg("Text column not found in search results")
return nil, fmt.Errorf("text column %s not found in search results", textField)
}
// Iterate over rows.
for i := 0; i < result.ResultCount; i++ {
// Get text value.
text, err := textCol.GetAsString(i)
if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Msg("Failed to parse text")
continue
}
// Get metadata value (optional).
var metadata map[string]interface{}
if metaCol != nil {
metaStr, err := metaCol.GetAsString(i)
if err == nil && metaStr != "" {
if err := json.Unmarshal([]byte(metaStr), &metadata); err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Msg("Failed to parse metadata")
continue
}
} else if err != nil {
log.Error().
Err(err).
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Msg("Failed to get metadata string")
}
}
// Ensure metadata includes user_id and username from query.
if metadata == nil {
metadata = make(map[string]interface{})
}
metadata[util.UserIdKey] = userId
metadata[util.UserNameKey] = userName
// Create document.
doc := ai.DocumentFromText(text, metadata)
docs = append(docs, doc)
log.Debug().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("index", i).
Str("text", text).
Interface("metadata", metadata).
Msg("Processed search result")
}
}
log.Info().
Str("method", "docStore.Retrieve").
Str("collection", ds.collection).
Int("documents", len(docs)).
Msg("Retrieve operation completed successfully")
return &ai.RetrieverResponse{
Documents: docs,
}, nil
}
// // Copyright 2025 Google LLC
// //
// // Licensed under the Apache License, Version 2.0 (the "License");
......
......@@ -9,7 +9,6 @@ import (
_ "github.com/lib/pq"
)
type QA struct {
ID int64 // 主键
CreatedAt time.Time // 创建时间
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment