This is an automated email from the ASF dual-hosted git repository.

robocanic pushed a commit to branch ai
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/ai by this push:
     new 60db2ded [feat]: Integrating AI Agent Capabilities into dubbo-admin
60db2ded is described below

commit 60db2dedacd2c873fb5d122789901fb53baf831f
Author: Liwen Chen <[email protected]>
AuthorDate: Wed Sep 3 19:34:03 2025 +0800

    [feat]: Integrating AI Agent Capabilities into dubbo-admin
    
    Integrating AI Agent Capabilities into dubbo-admin(#1319)
---
 ai/.env.example                       |   3 +
 ai/.gitignore                         |   6 +
 ai/README.md                          |   0
 ai/go.mod                             |  60 ++++
 ai/go.sum                             | 123 +++++++
 ai/internal/agent/flow.go             | 182 ++++++++++
 ai/internal/config/config.go          |  25 ++
 ai/internal/manager/manager.go        | 126 +++++++
 ai/internal/schema/llm_schema.go      | 102 ++++++
 ai/internal/tools/mock_tools.go       | 623 ++++++++++++++++++++++++++++++++++
 ai/internal/tools/tools.go            |  39 +++
 ai/main.go                            |  13 +
 ai/plugins/dashscope/dashscope.go     | 148 ++++++++
 ai/plugins/siliconflow/siliconflow.go | 141 ++++++++
 ai/prompts/agentSystem.prompt         |  90 +++++
 ai/prompts/menuPrompt.prompt          |  15 +
 ai/prompts/weatherPrompt.prompt       |  12 +
 ai/test/flow_test.go                  | 107 ++++++
 ai/test/llm_test.go                   |  66 ++++
 ai/test/test.go                       |  12 +
 ai/utils/utils.go                     |  52 +++
 21 files changed, 1945 insertions(+)

diff --git a/ai/.env.example b/ai/.env.example
new file mode 100644
index 00000000..7f47aff9
--- /dev/null
+++ b/ai/.env.example
@@ -0,0 +1,3 @@
+GEMINI_API_KEY=YOUR_API_KEY
+SILICONFLOW_API_KEY=YOUR_API_KEY
+DASHSCOPE_API_KEY=YOUR_API_KEY
\ No newline at end of file
diff --git a/ai/.gitignore b/ai/.gitignore
new file mode 100644
index 00000000..a96daa9e
--- /dev/null
+++ b/ai/.gitignore
@@ -0,0 +1,6 @@
+.idea
+.vscode
+.genkit
+.DS_Store
+
+.env
\ No newline at end of file
diff --git a/ai/README.md b/ai/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/ai/go.mod b/ai/go.mod
new file mode 100644
index 00000000..f0fa8b8d
--- /dev/null
+++ b/ai/go.mod
@@ -0,0 +1,60 @@
+module dubbo-admin-ai
+
+go 1.24.1
+
+toolchain go1.24.5
+
+require (
+       github.com/firebase/genkit/go v0.6.2
+       github.com/joho/godotenv v1.5.1
+       github.com/lmittmann/tint v1.1.2
+       github.com/openai/openai-go v0.1.0-alpha.65
+)
+
+require (
+       github.com/tidwall/gjson v1.18.0 // indirect
+       github.com/tidwall/match v1.1.1 // indirect
+       github.com/tidwall/pretty v1.2.1 // indirect
+       github.com/tidwall/sjson v1.2.5 // indirect
+)
+
+require (
+       cloud.google.com/go v0.120.0 // indirect
+       cloud.google.com/go/auth v0.16.2 // indirect
+       cloud.google.com/go/compute/metadata v0.7.0 // indirect
+       github.com/bahlo/generic-list-go v0.2.0 // indirect
+       github.com/buger/jsonparser v1.1.1 // indirect
+       github.com/felixge/httpsnoop v1.0.4 // indirect
+       github.com/go-logr/logr v1.4.3 // indirect
+       github.com/go-logr/stdr v1.2.2 // indirect
+       github.com/goccy/go-yaml v1.17.1 // indirect
+       github.com/google/dotprompt/go v0.0.0-20250611200215-bb73406b05ca // 
indirect
+       github.com/google/go-cmp v0.7.0 // indirect
+       github.com/google/s2a-go v0.1.9 // indirect
+       github.com/google/uuid v1.6.0 // indirect
+       github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
+       github.com/googleapis/gax-go/v2 v2.14.2 // indirect
+       github.com/gorilla/websocket v1.5.3 // indirect
+       github.com/invopop/jsonschema v0.13.0 // indirect
+       github.com/mailru/easyjson v0.9.0 // indirect
+       github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a // 
indirect
+       github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
+       github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // 
indirect
+       github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 
// indirect
+       github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+       go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+       go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 
// indirect
+       go.opentelemetry.io/otel v1.36.0 // indirect
+       go.opentelemetry.io/otel/metric v1.36.0 // indirect
+       go.opentelemetry.io/otel/sdk v1.36.0 // indirect
+       go.opentelemetry.io/otel/trace v1.36.0 // indirect
+       golang.org/x/crypto v0.41.0 // indirect
+       golang.org/x/net v0.43.0 // indirect
+       golang.org/x/sys v0.35.0 // indirect
+       golang.org/x/text v0.28.0 // indirect
+       google.golang.org/genai v1.11.1 // indirect
+       google.golang.org/genproto/googleapis/rpc 
v0.0.0-20250603155806-513f23925822 // indirect
+       google.golang.org/grpc v1.73.0 // indirect
+       google.golang.org/protobuf v1.36.6 // indirect
+       gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/ai/go.sum b/ai/go.sum
new file mode 100644
index 00000000..ab1e3298
--- /dev/null
+++ b/ai/go.sum
@@ -0,0 +1,123 @@
+cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
+cloud.google.com/go v0.120.0/go.mod 
h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q=
+cloud.google.com/go/auth v0.16.2 
h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
+cloud.google.com/go/auth v0.16.2/go.mod 
h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
+cloud.google.com/go/compute/metadata v0.7.0 
h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
+cloud.google.com/go/compute/metadata v0.7.0/go.mod 
h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
+github.com/bahlo/generic-list-go v0.2.0 
h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod 
h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
+github.com/buger/jsonparser v1.1.1 
h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
+github.com/buger/jsonparser v1.1.1/go.mod 
h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
+github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc 
h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/felixge/httpsnoop v1.0.4 
h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod 
h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/firebase/genkit/go v0.6.2 
h1:FaVJtcprfXZz0gXTtARJqUiovu/R2wuJycNn/18aNMc=
+github.com/firebase/genkit/go v0.6.2/go.mod 
h1:blRYK6oNgwBDX6F+gInACru6q527itviv+xruiMSUuU=
+github.com/go-logr/logr v1.2.2/go.mod 
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
+github.com/go-logr/logr v1.4.3/go.mod 
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod 
h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/goccy/go-yaml v1.17.1 
h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
+github.com/goccy/go-yaml v1.17.1/go.mod 
h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
+github.com/golang/protobuf v1.5.4 
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod 
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/dotprompt/go v0.0.0-20250611200215-bb73406b05ca 
h1:LuQ8KS5N04c37jyaq6jelLdNi0GfI6QJb8lpnYaDW9Y=
+github.com/google/dotprompt/go v0.0.0-20250611200215-bb73406b05ca/go.mod 
h1:dnIk+MSMnipm9uZyPIgptq7I39aDxyjBiaev/OG0W0Y=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod 
h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
+github.com/google/s2a-go v0.1.9/go.mod 
h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod 
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.3.6 
h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
+github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod 
h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
+github.com/googleapis/gax-go/v2 v2.14.2 
h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
+github.com/googleapis/gax-go/v2 v2.14.2/go.mod 
h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
+github.com/gorilla/websocket v1.5.3 
h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod 
h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/invopop/jsonschema v0.13.0 
h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
+github.com/invopop/jsonschema v0.13.0/go.mod 
h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
+github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
+github.com/joho/godotenv v1.5.1/go.mod 
h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod 
h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod 
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lmittmann/tint v1.1.2 
h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
+github.com/lmittmann/tint v1.1.2/go.mod 
h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
+github.com/mailru/easyjson v0.9.0 
h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
+github.com/mailru/easyjson v0.9.0/go.mod 
h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
+github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a 
h1:v2cBA3xWKv2cIOVhnzX/gNgkNXqiHfUgJtA3r61Hf7A=
+github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a/go.mod 
h1:Y6ghKH+ZijXn5d9E7qGGZBmjitx7iitZdQiIW97EpTU=
+github.com/openai/openai-go v0.1.0-alpha.65 
h1:G12sA6OaL+cVMElMO3m5RVFwKhhg40kmGeGhaYZIoYw=
+github.com/openai/openai-go v0.1.0-alpha.65/go.mod 
h1:3SdE6BffOX9HPEQv8IL/fi3LYZ5TUpRYaqGQZbyk11A=
+github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 
h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.13.1 
h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod 
h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.10.0 
h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod 
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tidwall/gjson v1.14.2/go.mod 
h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.18.0 
h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
+github.com/tidwall/gjson v1.18.0/go.mod 
h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod 
h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0/go.mod 
h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/pretty v1.2.1 
h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
+github.com/tidwall/pretty v1.2.1/go.mod 
h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
+github.com/tidwall/sjson v1.2.5/go.mod 
h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
+github.com/wk8/go-ordered-map/v2 v2.1.8 
h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
+github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod 
h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod 
h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb 
h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod 
h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 
h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod 
h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 
h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod 
h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+go.opentelemetry.io/auto/sdk v1.1.0 
h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod 
h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 
h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod 
h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
+go.opentelemetry.io/otel v1.36.0 
h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
+go.opentelemetry.io/otel v1.36.0/go.mod 
h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
+go.opentelemetry.io/otel/metric v1.36.0 
h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
+go.opentelemetry.io/otel/metric v1.36.0/go.mod 
h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
+go.opentelemetry.io/otel/sdk v1.36.0 
h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
+go.opentelemetry.io/otel/sdk v1.36.0/go.mod 
h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
+go.opentelemetry.io/otel/sdk/metric v1.36.0 
h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
+go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod 
h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
+go.opentelemetry.io/otel/trace v1.36.0 
h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
+go.opentelemetry.io/otel/trace v1.36.0/go.mod 
h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod 
h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod 
h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
+golang.org/x/sync v0.16.0/go.mod 
h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod 
h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
+google.golang.org/genai v1.11.1 h1:MgI2JVDaIQ1YMuzKFwgPciB+K6kQ8MCBMVL9u7Oa8qw=
+google.golang.org/genai v1.11.1/go.mod 
h1:HFXR1zT3LCdLxd/NW6IOSCczOYyRAxwaShvYbgPSeVw=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 
h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
+google.golang.org/genproto/googleapis/rpc 
v0.0.0-20250603155806-513f23925822/go.mod 
h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
+google.golang.org/grpc v1.73.0/go.mod 
h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
+google.golang.org/protobuf v1.36.6 
h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod 
h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod 
h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/ai/internal/agent/flow.go b/ai/internal/agent/flow.go
new file mode 100644
index 00000000..e39e359e
--- /dev/null
+++ b/ai/internal/agent/flow.go
@@ -0,0 +1,182 @@
+package agent
+
+import (
+       "context"
+
+       "dubbo-admin-ai/internal/config"
+       "dubbo-admin-ai/internal/manager"
+       "dubbo-admin-ai/internal/schema"
+       "dubbo-admin-ai/internal/tools"
+       "errors"
+       "fmt"
+       "log"
+       "os"
+
+       "github.com/firebase/genkit/go/core/logger"
+
+       "github.com/firebase/genkit/go/ai"
+       "github.com/firebase/genkit/go/core"
+       "github.com/firebase/genkit/go/genkit"
+)
+
+// 公开的 Flow 变量,以便在编排器中调用
+var (
+       ReActFlow    *core.Flow[schema.ReActIn, schema.ReActOut, struct{}]
+       ThinkingFlow *core.Flow[schema.ThinkIn, *schema.ThinkOut, struct{}]
+       ActFlow      *core.Flow[*schema.ActIn, schema.ActOut, struct{}]
+
+       ThinkPrompt *ai.Prompt
+)
+
+var g *genkit.Genkit
+
+// The order of initialization cannot change
+func InitAgent(defaultModel string) (err error) {
+       if err = manager.LoadEnvVars(); err != nil {
+               return err
+       }
+
+       manager.InitLogger()
+       if err := manager.InitGlobalGenkit(defaultModel); err != nil {
+               return err
+       }
+
+       if g, err = manager.GetGlobalGenkit(); err != nil {
+               return err
+       }
+
+       tools.RegisterAllMockTools(g)
+
+       if err = InitFlows(g); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func InitFlows(registry *genkit.Genkit) error {
+       if registry == nil {
+               return fmt.Errorf("registry is nil")
+       }
+       g = registry
+
+       data, err := os.ReadFile(config.PROMPT_DIR_PATH + "/agentSystem.prompt")
+       if err != nil {
+               return fmt.Errorf("failed to read agentSystem prompt: %w", err)
+       }
+       systemPromptText := string(data)
+
+       mockTools, err := tools.AllMockToolRef()
+       if err != nil {
+               log.Fatalf("failed to get mock mock_tools: %v", err)
+       }
+       ThinkPrompt, err = genkit.DefinePrompt(g, "agentThinking",
+               ai.WithSystem(systemPromptText),
+               ai.WithInputType(schema.ThinkIn{}),
+               ai.WithOutputType(schema.ThinkOut{}),
+               ai.WithPrompt("{{userInput}}"),
+               ai.WithTools(mockTools...),
+       )
+
+       if err != nil {
+               return fmt.Errorf("failed to define agentThink prompt: %w", err)
+       }
+
+       ReActFlow = genkit.DefineFlow(g, "reAct", reAct)
+       ThinkingFlow = genkit.DefineFlow(g, "thinking", thinking)
+       ActFlow = genkit.DefineFlow(g, "act", act)
+
+       return nil
+}
+
+// Flow 的核心函数实现 `fn` (不对外导出)
+// ----------------------------------------------------------------------------
+// 1. agentOrchestrator: 总指挥/编排器的核心逻辑
+// ----------------------------------------------------------------------------
+func reAct(ctx context.Context, reActInput schema.ReActIn) (reActOut 
schema.ReActOut, err error) {
+       //TODO: 输入数据意图解析
+
+       thinkingInput := reActInput
+       // 主协调循环 (Reconciliation Loop)
+       for i := 0; i < config.MAX_REACT_ITERATIONS; i++ {
+
+               // a. 调用 thinkingFlow
+               thinkingResp, err := ThinkingFlow.Run(ctx, thinkingInput)
+               if err != nil {
+                       manager.GetLogger().Error("failed to run thinking 
flow", "error", err)
+                       return "", err
+               }
+               if thinkingResp == nil {
+                       manager.GetLogger().Error("expected non-nil response")
+                       return "", errors.New("expected non-nil response")
+               }
+
+               for _, r := range thinkingResp.ToolRequests {
+                       manager.GetLogger().Info(r.String())
+               }
+
+               reActOut = thinkingResp.String()
+
+               // b. 检查是否有最终答案
+               if thinkingResp.IsStop() {
+                       break
+               }
+
+               // c. 调用 actFlow
+               actOutArray, err := ActFlow.Run(ctx, thinkingResp)
+               if err != nil {
+                       logger.FromContext(ctx).Error("failed to run act flow", 
"error", err)
+                       return "", err
+               }
+
+               // TODO: 这里将来会集成SessionMemory,暂时简化处理
+               _ = actOutArray // 占位符,避免未使用变量错误
+       }
+
+       return reActOut, nil
+}
+
+// ----------------------------------------------------------------------------
+// 2. thinking: 大脑/思考者的核心逻辑
+// ----------------------------------------------------------------------------
+func thinking(ctx context.Context, input schema.ThinkIn) (*schema.ThinkOut, 
error) {
+       resp, err := ThinkPrompt.Execute(ctx,
+               ai.WithInput(input),
+       )
+
+       if err != nil {
+               return nil, fmt.Errorf("failed to execute agentThink prompt: 
%w", err)
+       }
+
+       // 解析输出
+       var response *schema.ThinkOut
+       err = resp.Output(&response)
+       if err != nil {
+               return nil, fmt.Errorf("failed to parse agentThink prompt 
response: %w", err)
+       }
+
+       return response, nil
+}
+
+// ----------------------------------------------------------------------------
+// 3. act: 执行者的核心逻辑
+// TODO: Genkit 的 Tool 设计不能保证任意 LLM 一定能执行工具调用,是否考虑设计成所有模型都能执行?
+// 一种思路是让 LLM 直接生成工具调用的结构化描述,然后由适配器执行。
+// 管线、流水线的思想能否用在这里?
+func act(ctx context.Context, actIn *schema.ActIn) (schema.ActOut, error) {
+       var actOutArray schema.ActOut
+       // 执行工具调用
+       for _, resp := range actIn.ToolRequests {
+               if err := resp.ValidateToolDesc(); err != nil {
+                       return nil, fmt.Errorf("invalid tool description in 
action response: %w", err)
+               }
+
+               output, err := resp.ToolDesc.Call(g, ctx)
+               if err != nil {
+                       return nil, fmt.Errorf("failed to call tool %s: %w", 
resp.ToolDesc.ToolName, err)
+               }
+               actOutArray = append(actOutArray, output)
+       }
+
+       return actOutArray, nil
+}
diff --git a/ai/internal/config/config.go b/ai/internal/config/config.go
new file mode 100644
index 00000000..b071b846
--- /dev/null
+++ b/ai/internal/config/config.go
@@ -0,0 +1,25 @@
+package config
+
+import (
+       "dubbo-admin-ai/plugins/siliconflow"
+       "os"
+       "path/filepath"
+       "runtime"
+)
+
+var (
+       // API keys
+       GEMINI_API_KEY      string = os.Getenv("GEMINI_API_KEY")
+       SILICONFLOW_API_KEY string = os.Getenv("SILICONFLOW_API_KEY")
+       DASHSCOPE_API_KEY   string = os.Getenv("DASHSCOPE_API_KEY")
+
+       // Configuration
+       // 自动获取项目根目录
+       _, b, _, _   = runtime.Caller(0)
+       PROJECT_ROOT = filepath.Join(filepath.Dir(b), "..", "..")
+
+       PROMPT_DIR_PATH      string = filepath.Join(PROJECT_ROOT, "prompts")
+       LOG_LEVEL            string = os.Getenv("LOG_LEVEL")
+       DEFAULT_MODEL        string = siliconflow.DeepSeekV3
+       MAX_REACT_ITERATIONS int    = 5
+)
diff --git a/ai/internal/manager/manager.go b/ai/internal/manager/manager.go
new file mode 100644
index 00000000..2c0e8d17
--- /dev/null
+++ b/ai/internal/manager/manager.go
@@ -0,0 +1,126 @@
+package manager
+
+import (
+       "context"
+
+       "dubbo-admin-ai/internal/config"
+
+       "dubbo-admin-ai/plugins/dashscope"
+       "dubbo-admin-ai/plugins/siliconflow"
+       "dubbo-admin-ai/utils"
+       "fmt"
+       "log/slog"
+       "os"
+       "path/filepath"
+       "strings"
+       "time"
+
+       "github.com/firebase/genkit/go/core/logger"
+       "github.com/firebase/genkit/go/genkit"
+       "github.com/firebase/genkit/go/plugins/googlegenai"
+       "github.com/joho/godotenv"
+       "github.com/lmittmann/tint"
+)
+
+var (
+       globalGenkit *genkit.Genkit
+       rootContext  *context.Context
+       globalLogger *slog.Logger
+)
+
+func InitGlobalGenkit(defaultModel string) (err error) {
+       ctx := context.Background()
+       if rootContext == nil {
+               rootContext = &ctx
+       }
+       g, err := genkit.Init(*rootContext,
+               genkit.WithPlugins(
+                       &siliconflow.SiliconFlow{
+                               APIKey: config.SILICONFLOW_API_KEY,
+                       },
+                       &googlegenai.GoogleAI{
+                               APIKey: config.GEMINI_API_KEY,
+                       },
+                       &dashscope.DashScope{
+                               APIKey: config.DASHSCOPE_API_KEY,
+                       },
+               ),
+               genkit.WithDefaultModel(defaultModel),
+               genkit.WithPromptDir(config.PROMPT_DIR_PATH),
+       )
+
+       if g == nil {
+               return fmt.Errorf("fail to initialize global genkit")
+       }
+
+       globalGenkit = g
+       return err
+}
+
+func InitLogger() {
+       logLevel := slog.LevelInfo
+       if envLevel := config.LOG_LEVEL; envLevel != "" {
+               switch strings.ToUpper(envLevel) {
+               case "DEBUG":
+                       logLevel = slog.LevelDebug
+               case "INFO":
+                       logLevel = slog.LevelInfo
+               case "WARN", "WARNING":
+                       logLevel = slog.LevelWarn
+               case "ERROR":
+                       logLevel = slog.LevelError
+               }
+       }
+       logger.SetLevel(logLevel)
+
+       slog.SetDefault(
+               slog.New(
+                       tint.NewHandler(os.Stderr, &tint.Options{
+                               Level:      slog.LevelDebug,
+                               AddSource:  true,
+                               TimeFormat: time.Kitchen,
+                       }),
+               ),
+       )
+       globalLogger = slog.Default()
+}
+
+func GetGlobalGenkit() (*genkit.Genkit, error) {
+       var err error
+       if globalGenkit == nil {
+               return nil, fmt.Errorf("global genkit is nil, initialize genkit 
first")
+       }
+       return globalGenkit, err
+}
+
+func GetLogger() *slog.Logger {
+       if globalLogger == nil {
+               InitLogger()
+       }
+       return globalLogger
+}
+
+func GetRootContext() context.Context {
+       ctx := context.Background()
+       if rootContext == nil {
+               rootContext = &ctx
+       }
+       return *rootContext
+}
+
+// Load environment variables from PROJECT_ROOT/.env file
+func LoadEnvVars() (err error) {
+       dotEnvFilePath := filepath.Join(config.PROJECT_ROOT, ".env")
+       dotEnvExampleFilePath := filepath.Join(config.PROJECT_ROOT, 
".env.example")
+
+       // Check if the .env file exists, if not, copy .env.example to .env
+       if _, err = os.Stat(dotEnvFilePath); os.IsNotExist(err) {
+               if err = utils.CopyFile(dotEnvExampleFilePath, dotEnvFilePath); 
err != nil {
+                       return err
+               }
+       }
+
+       // Load environment variables
+       err = godotenv.Load(dotEnvFilePath)
+       return err
+}
diff --git a/ai/internal/schema/llm_schema.go b/ai/internal/schema/llm_schema.go
new file mode 100644
index 00000000..f54f1f7d
--- /dev/null
+++ b/ai/internal/schema/llm_schema.go
@@ -0,0 +1,102 @@
+package schema
+
+import (
+       "dubbo-admin-ai/internal/tools"
+       "encoding/json"
+       "fmt"
+)
+
+// 表示 LLM 的响应结构
+type ReActIn = ReActInput
+type ReActOut = string
+
+type ThinkIn = ReActInput
+type ThinkOut = ThinkAggregation
+
+type ActIn = ThinkOut
+type ActOut = []string
+
+type ReActInput struct {
+       UserInput string `json:"userInput"`
+       // 移除SessionID和SessionMemory,这些由Session管理
+}
+
+type Status string
+
+const (
+       Continued Status = "CONTINUED"
+       Finished  Status = "FINISHED"
+       Pending   Status = "PENDING"
+)
+
+type ToolRequest struct {
+       Thought  string         `json:"thought"`
+       ToolDesc tools.ToolDesc `json:"tool_desc"`
+}
+
+type ThinkAggregation struct {
+       ToolRequests []ToolRequest `json:"tool_requests"`
+       Status       Status        `json:"status" 
jsonschema:"enum=CONTINUED,enum=FINISHED,enum=PENDING"`
+       Thought      string        `json:"thought"`
+       FinalAnswer  string        `json:"final_answer,omitempty" 
jsonschema:"required=false"`
+}
+
+// ReActInput
+func (a ReActInput) String() string {
+       data, err := json.MarshalIndent(a, "", "  ")
+       if err != nil {
+               return fmt.Sprintf("ReActInput{error: %v}", err)
+       }
+       return string(data)
+}
+
+// ToolRequest
+// HasAction 检查是否包含行动指令
+func (tr ToolRequest) HasAction() bool {
+       return tr.ToolDesc.ToolInput != nil && tr.ToolDesc.ToolName != ""
+}
+
+// ValidateToolDesc 验证行动指令的有效性
+func (tr ToolRequest) ValidateToolDesc() error {
+       if !tr.HasAction() {
+               return fmt.Errorf("no valid action found")
+       }
+
+       if tr.ToolDesc.ToolName == "" {
+               return fmt.Errorf("tool_name cannot be empty")
+       }
+
+       // 验证支持的工具名称
+       supportedTools, err := tools.AllMockToolNames()
+       if err != nil {
+               return fmt.Errorf("failed to get supported tools: %w", err)
+       }
+
+       if _, ok := supportedTools[tr.ToolDesc.ToolName]; !ok {
+               return fmt.Errorf("unsupported tool: %s", tr.ToolDesc.ToolName)
+       }
+
+       return nil
+}
+
+// String 实现 fmt.Stringer 接口,返回格式化的 JSON
+func (tr ToolRequest) String() string {
+       data, err := json.MarshalIndent(tr, "", "  ")
+       if err != nil {
+               return fmt.Sprintf("ToolRequest{error: %v}", err)
+       }
+       return string(data)
+}
+
+// ThinkAggregation
+func (ta ThinkAggregation) IsStop() bool {
+       return ta.Status == Finished && ta.FinalAnswer != ""
+}
+
+func (ta ThinkAggregation) String() string {
+       data, err := json.MarshalIndent(ta, "", "  ")
+       if err != nil {
+               return fmt.Sprintf("ThinkAggregation{error: %v}", err)
+       }
+       return string(data)
+}
diff --git a/ai/internal/tools/mock_tools.go b/ai/internal/tools/mock_tools.go
new file mode 100644
index 00000000..d61663b2
--- /dev/null
+++ b/ai/internal/tools/mock_tools.go
@@ -0,0 +1,623 @@
+package tools
+
+import (
+       "fmt"
+       "log"
+
+       "github.com/firebase/genkit/go/ai"
+       "github.com/firebase/genkit/go/genkit"
+)
+
+// ================================================
+// Prometheus Query Service Latency Tool
+// ================================================
+type ToolOutput interface {
+       Tool() string
+}
+
+type PrometheusServiceLatencyInput struct {
+       ServiceName      string  `json:"serviceName" 
jsonschema:"required,description=The name of the service to query"`
+       TimeRangeMinutes int     `json:"timeRangeMinutes" 
jsonschema:"required,description=Time range in minutes"`
+       Quantile         float64 `json:"quantile" 
jsonschema:"required,description=Quantile to query (e.g., 0.99 or 0.95)"`
+}
+
+type PrometheusServiceLatencyOutput struct {
+       ToolName    string  `json:"toolName"`
+       Quantile    float64 `json:"quantile"`
+       ValueMillis int     `json:"valueMillis"`
+       Summary     string  `json:"summary"`
+}
+
+func (o PrometheusServiceLatencyOutput) Tool() string {
+       return o.ToolName
+}
+
+func prometheusQueryServiceLatency(ctx *ai.ToolContext, input 
PrometheusServiceLatencyInput) (PrometheusServiceLatencyOutput, error) {
+       log.Printf("Tool 'prometheus_query_service_latency' called for service: 
%s", input.ServiceName)
+
+       // Mock data based on the example in prompt
+       valueMillis := 3500
+       if input.ServiceName != "order-service" {
+               valueMillis = 850
+       }
+
+       return PrometheusServiceLatencyOutput{
+               ToolName:    "prometheus_query_service_latency",
+               Quantile:    input.Quantile,
+               ValueMillis: valueMillis,
+               Summary:     fmt.Sprintf("服务 %s 在过去%d分钟内的 P%.0f 延迟为 %dms", 
input.ServiceName, input.TimeRangeMinutes, input.Quantile*100, valueMillis),
+       }, nil
+}
+
+// ================================================
+// Prometheus Query Service Traffic Tool
+// ================================================
+
+type PrometheusServiceTrafficInput struct {
+       ServiceName      string `json:"serviceName" 
jsonschema:"required,description=The name of the service to query"`
+       TimeRangeMinutes int    `json:"timeRangeMinutes" 
jsonschema:"required,description=Time range in minutes"`
+}
+
+type PrometheusServiceTrafficOutput struct {
+       ToolName            string  `json:"toolName"`
+       RequestRateQPS      float64 `json:"requestRateQPS"`
+       ErrorRatePercentage float64 `json:"errorRatePercentage"`
+       Summary             string  `json:"summary"`
+}
+
+func (o PrometheusServiceTrafficOutput) Tool() string {
+       return o.ToolName
+}
+
+func prometheusQueryServiceTraffic(ctx *ai.ToolContext, input 
PrometheusServiceTrafficInput) (PrometheusServiceTrafficOutput, error) {
+       log.Printf("Tool 'prometheus_query_service_traffic' called for service: 
%s", input.ServiceName)
+
+       return PrometheusServiceTrafficOutput{
+               ToolName:            "prometheus_query_service_traffic",
+               RequestRateQPS:      250.0,
+               ErrorRatePercentage: 5.2,
+               Summary:             fmt.Sprintf("服务 %s 的 QPS 为 250, 错误率为 
5.2%%", input.ServiceName),
+       }, nil
+}
+
+// ================================================
+// Query Timeseries Database Tool
+// ================================================
+
+type QueryTimeseriesDatabaseInput struct {
+       PromqlQuery string `json:"promqlQuery" 
jsonschema:"required,description=PromQL query to execute"`
+}
+
+type TimeseriesMetric struct {
+       Pod string `json:"pod"`
+}
+
+type TimeseriesValue struct {
+       Timestamp int64  `json:"timestamp"`
+       Value     string `json:"value"`
+}
+
+type TimeseriesResult struct {
+       Metric TimeseriesMetric `json:"metric"`
+       Value  TimeseriesValue  `json:"value"`
+}
+
+type QueryTimeseriesDatabaseOutput struct {
+       ToolName string             `json:"toolName"`
+       Query    string             `json:"query"`
+       Results  []TimeseriesResult `json:"results"`
+       Summary  string             `json:"summary"`
+}
+
+func (o QueryTimeseriesDatabaseOutput) Tool() string {
+       return o.ToolName
+}
+
+func queryTimeseriesDatabase(ctx *ai.ToolContext, input 
QueryTimeseriesDatabaseInput) (QueryTimeseriesDatabaseOutput, error) {
+       log.Printf("Tool 'query_timeseries_database' called with query: %s", 
input.PromqlQuery)
+
+       return QueryTimeseriesDatabaseOutput{
+               ToolName: "query_timeseries_database",
+               Query:    input.PromqlQuery,
+               Results: []TimeseriesResult{
+                       {
+                               Metric: TimeseriesMetric{Pod: 
"order-service-pod-1"},
+                               Value:  TimeseriesValue{Timestamp: 1692192000, 
Value: "3.5"},
+                       },
+                       {
+                               Metric: TimeseriesMetric{Pod: 
"order-service-pod-2"},
+                               Value:  TimeseriesValue{Timestamp: 1692192000, 
Value: "3.2"},
+                       },
+               },
+               Summary: "查询返回了 2 个时间序列",
+       }, nil
+}
+
+// ================================================
+// Application Performance Profiling Tool
+// ================================================
+
+type ApplicationPerformanceProfilingInput struct {
+       ServiceName     string `json:"serviceName" 
jsonschema:"required,description=The name of the service to profile"`
+       PodName         string `json:"podName" 
jsonschema:"required,description=The specific pod name to profile"`
+       DurationSeconds int    `json:"durationSeconds" 
jsonschema:"required,description=Duration of profiling in seconds"`
+}
+
+type PerformanceHotspot struct {
+       CPUTimePercentage float64  `json:"cpuTimePercentage"`
+       StackTrace        []string `json:"stackTrace"`
+}
+
+type ApplicationPerformanceProfilingOutput struct {
+       ToolName     string               `json:"toolName"`
+       Status       string               `json:"status"`
+       TotalSamples int                  `json:"totalSamples"`
+       Hotspots     []PerformanceHotspot `json:"hotspots"`
+       Summary      string               `json:"summary"`
+}
+
+func (o ApplicationPerformanceProfilingOutput) Tool() string {
+       return o.ToolName
+}
+
+func applicationPerformanceProfiling(ctx *ai.ToolContext, input 
ApplicationPerformanceProfilingInput) (ApplicationPerformanceProfilingOutput, 
error) {
+       log.Printf("Tool 'application_performance_profiling' called for 
service: %s, pod: %s", input.ServiceName, input.PodName)
+
+       return ApplicationPerformanceProfilingOutput{
+               ToolName:     "application_performance_profiling",
+               Status:       "completed",
+               TotalSamples: 10000,
+               Hotspots: []PerformanceHotspot{
+                       {
+                               CPUTimePercentage: 45.5,
+                               StackTrace: []string{
+                                       
"com.example.OrderService.processOrder()",
+                                       "com.example.DatabaseClient.query()",
+                                       
"java.sql.PreparedStatement.executeQuery()",
+                               },
+                       },
+               },
+               Summary: "性能分析显示,45.5%的CPU时间消耗在数据库查询调用链上",
+       }, nil
+}
+
+// ================================================
+// JVM Performance Analysis Tool
+// ================================================
+
+type JVMPerformanceAnalysisInput struct {
+       ServiceName string `json:"serviceName" 
jsonschema:"required,description=The name of the Java service to analyze"`
+       PodName     string `json:"podName" jsonschema:"required,description=The 
specific pod name to analyze"`
+}
+
+type JVMPerformanceAnalysisOutput struct {
+       ToolName            string  `json:"toolName"`
+       FullGcCountLastHour int     `json:"fullGcCountLastHour"`
+       FullGcTimeAvgMillis int     `json:"fullGcTimeAvgMillis"`
+       HeapUsagePercentage float64 `json:"heapUsagePercentage"`
+       Summary             string  `json:"summary"`
+}
+
+func (o JVMPerformanceAnalysisOutput) Tool() string {
+       return o.ToolName
+}
+
+func jvmPerformanceAnalysis(ctx *ai.ToolContext, input 
JVMPerformanceAnalysisInput) (JVMPerformanceAnalysisOutput, error) {
+       log.Printf("Tool 'jvm_performance_analysis' called for service: %s, 
pod: %s", input.ServiceName, input.PodName)
+
+       return JVMPerformanceAnalysisOutput{
+               ToolName:            "jvm_performance_analysis",
+               FullGcCountLastHour: 15,
+               FullGcTimeAvgMillis: 1200,
+               HeapUsagePercentage: 85.5,
+               Summary:             "GC activity is high, average Full GC time 
is 1200ms",
+       }, nil
+}
+
+// ================================================
+// Trace Dependency View Tool
+// ================================================
+
+type TraceDependencyViewInput struct {
+       ServiceName string `json:"serviceName" 
jsonschema:"required,description=The name of the service to analyze 
dependencies"`
+}
+
+type TraceDependencyViewOutput struct {
+       ToolName           string   `json:"toolName"`
+       UpstreamServices   []string `json:"upstreamServices"`
+       DownstreamServices []string `json:"downstreamServices"`
+}
+
+func (o TraceDependencyViewOutput) Tool() string {
+       return o.ToolName
+}
+
+func traceDependencyView(ctx *ai.ToolContext, input TraceDependencyViewInput) 
(TraceDependencyViewOutput, error) {
+       log.Printf("Tool 'trace_dependency_view' called for service: %s", 
input.ServiceName)
+
+       return TraceDependencyViewOutput{
+               ToolName:           "trace_dependency_view",
+               UpstreamServices:   []string{"api-gateway", "user-service"},
+               DownstreamServices: []string{"mysql-orders-db", "redis-cache", 
"payment-service"},
+       }, nil
+}
+
+// ================================================
+// Trace Latency Analysis Tool
+// ================================================
+
+type TraceLatencyAnalysisInput struct {
+       ServiceName      string `json:"serviceName" 
jsonschema:"required,description=The name of the service to analyze"`
+       TimeRangeMinutes int    `json:"timeRangeMinutes" 
jsonschema:"required,description=Time range in minutes"`
+}
+
+type LatencyBottleneck struct {
+       DownstreamService      string  `json:"downstreamService"`
+       LatencyAvgMillis       int     `json:"latencyAvgMillis"`
+       ContributionPercentage float64 `json:"contributionPercentage"`
+}
+
+type TraceLatencyAnalysisOutput struct {
+       ToolName              string              `json:"toolName"`
+       TotalLatencyAvgMillis int                 `json:"totalLatencyAvgMillis"`
+       Bottlenecks           []LatencyBottleneck `json:"bottlenecks"`
+       Summary               string              `json:"summary"`
+}
+
+func (o TraceLatencyAnalysisOutput) Tool() string {
+       return o.ToolName
+}
+
+func traceLatencyAnalysis(ctx *ai.ToolContext, input 
TraceLatencyAnalysisInput) (TraceLatencyAnalysisOutput, error) {
+       log.Printf("Tool 'trace_latency_analysis' called for service: %s", 
input.ServiceName)
+
+       return TraceLatencyAnalysisOutput{
+               ToolName:              "trace_latency_analysis",
+               TotalLatencyAvgMillis: 3200,
+               Bottlenecks: []LatencyBottleneck{
+                       {
+                               DownstreamService:      "mysql-orders-db",
+                               LatencyAvgMillis:       3050,
+                               ContributionPercentage: 95.3,
+                       },
+                       {
+                               DownstreamService:      "user-service",
+                               LatencyAvgMillis:       150,
+                               ContributionPercentage: 4.7,
+                       },
+               },
+               Summary: "平均总延迟为 3200ms。瓶颈已定位,95.3% 的延迟来自对下游 'mysql-orders-db' 
的调用",
+       }, nil
+}
+
+// ================================================
+// Database Connection Pool Analysis Tool
+// ================================================
+
+type DatabaseConnectionPoolAnalysisInput struct {
+       ServiceName string `json:"serviceName" 
jsonschema:"required,description=The name of the service to analyze"`
+}
+
+type DatabaseConnectionPoolAnalysisOutput struct {
+       ToolName          string `json:"toolName"`
+       MaxConnections    int    `json:"maxConnections"`
+       ActiveConnections int    `json:"activeConnections"`
+       IdleConnections   int    `json:"idleConnections"`
+       PendingRequests   int    `json:"pendingRequests"`
+       Summary           string `json:"summary"`
+}
+
+func (o DatabaseConnectionPoolAnalysisOutput) Tool() string {
+       return o.ToolName
+}
+
+func databaseConnectionPoolAnalysis(ctx *ai.ToolContext, input 
DatabaseConnectionPoolAnalysisInput) (DatabaseConnectionPoolAnalysisOutput, 
error) {
+       log.Printf("Tool 'database_connection_pool_analysis' called for 
service: %s", input.ServiceName)
+
+       return DatabaseConnectionPoolAnalysisOutput{
+               ToolName:          "database_connection_pool_analysis",
+               MaxConnections:    100,
+               ActiveConnections: 100,
+               IdleConnections:   0,
+               PendingRequests:   58,
+               Summary:           "数据库连接池已完全耗尽 (100/100),当前有 58 个请求正在排队等待连接",
+       }, nil
+}
+
+// ================================================
+// Kubernetes Get Pod Resources Tool
+// ================================================
+
+type KubernetesGetPodResourcesInput struct {
+       ServiceName string `json:"serviceName" 
jsonschema:"required,description=The name of the service"`
+       Namespace   string `json:"namespace" 
jsonschema:"required,description=The namespace of the service"`
+}
+
+type PodResource struct {
+       PodName         string  `json:"podName"`
+       CPUUsageCores   float64 `json:"cpuUsageCores"`
+       CPURequestCores float64 `json:"cpuRequestCores"`
+       CPULimitCores   float64 `json:"cpuLimitCores"`
+       MemoryUsageMi   int     `json:"memoryUsageMi"`
+       MemoryRequestMi int     `json:"memoryRequestMi"`
+       MemoryLimitMi   int     `json:"memoryLimitMi"`
+}
+
+type KubernetesGetPodResourcesOutput struct {
+       ToolName string        `json:"toolName"`
+       Pods     []PodResource `json:"pods"`
+       Summary  string        `json:"summary"`
+}
+
+func (o KubernetesGetPodResourcesOutput) Tool() string {
+       return o.ToolName
+}
+
+func kubernetesGetPodResources(ctx *ai.ToolContext, input 
KubernetesGetPodResourcesInput) (KubernetesGetPodResourcesOutput, error) {
+       log.Printf("Tool 'kubernetes_get_pod_resources' called for service: %s 
in namespace: %s", input.ServiceName, input.Namespace)
+
+       return KubernetesGetPodResourcesOutput{
+               ToolName: "kubernetes_get_pod_resources",
+               Pods: []PodResource{
+                       {
+                               PodName:         "order-service-pod-1",
+                               CPUUsageCores:   0.8,
+                               CPURequestCores: 0.5,
+                               CPULimitCores:   1.0,
+                               MemoryUsageMi:   1800,
+                               MemoryRequestMi: 1024,
+                               MemoryLimitMi:   2048,
+                       },
+                       {
+                               PodName:         "order-service-pod-2",
+                               CPUUsageCores:   0.9,
+                               CPURequestCores: 0.5,
+                               CPULimitCores:   1.0,
+                               MemoryUsageMi:   1950,
+                               MemoryRequestMi: 1024,
+                               MemoryLimitMi:   2048,
+                       },
+               },
+               Summary: "2 out of 2 pods are near their memory limits",
+       }, nil
+}
+
+// ================================================
+// Dubbo Service Status Tool
+// ================================================
+
+type DubboServiceStatusInput struct {
+       ServiceName string `json:"serviceName" 
jsonschema:"required,description=The name of the Dubbo service"`
+}
+
+type DubboProvider struct {
+       IP     string `json:"ip"`
+       Port   int    `json:"port"`
+       Status string `json:"status"`
+}
+
+type DubboConsumer struct {
+       IP          string `json:"ip"`
+       Application string `json:"application"`
+       Status      string `json:"status"`
+}
+
+type DubboServiceStatusOutput struct {
+       ToolName  string          `json:"toolName"`
+       Providers []DubboProvider `json:"providers"`
+       Consumers []DubboConsumer `json:"consumers"`
+}
+
+func (o DubboServiceStatusOutput) Tool() string {
+       return o.ToolName
+}
+
+func dubboServiceStatus(ctx *ai.ToolContext, input DubboServiceStatusInput) 
(DubboServiceStatusOutput, error) {
+       log.Printf("Tool 'dubbo_service_status' called for service: %s", 
input.ServiceName)
+
+       return DubboServiceStatusOutput{
+               ToolName: "dubbo_service_status",
+               Providers: []DubboProvider{
+                       {IP: "192.168.1.10", Port: 20880, Status: "healthy"},
+                       {IP: "192.168.1.11", Port: 20880, Status: "healthy"},
+               },
+               Consumers: []DubboConsumer{
+                       {IP: "192.168.1.20", Application: "web-frontend", 
Status: "connected"},
+                       {IP: "192.168.1.21", Application: "api-gateway", 
Status: "connected"},
+               },
+       }, nil
+}
+
+// ================================================
+// Query Log Database Tool
+// ================================================
+
+type QueryLogDatabaseInput struct {
+       ServiceName      string `json:"serviceName" 
jsonschema:"required,description=The name of the service"`
+       Keyword          string `json:"keyword" 
jsonschema:"required,description=Keyword to search for"`
+       TimeRangeMinutes int    `json:"timeRangeMinutes" 
jsonschema:"required,description=Time range in minutes"`
+}
+
+type LogEntry struct {
+       Timestamp string `json:"timestamp"`
+       Level     string `json:"level"`
+       Message   string `json:"message"`
+}
+
+type QueryLogDatabaseOutput struct {
+       ToolName  string     `json:"toolName"`
+       TotalHits int        `json:"totalHits"`
+       Logs      []LogEntry `json:"logs"`
+       Summary   string     `json:"summary"`
+}
+
+func (o QueryLogDatabaseOutput) Tool() string {
+       return o.ToolName
+}
+
+func queryLogDatabase(ctx *ai.ToolContext, input QueryLogDatabaseInput) 
(QueryLogDatabaseOutput, error) {
+       log.Printf("Tool 'query_log_database' called for service: %s, keyword: 
%s", input.ServiceName, input.Keyword)
+
+       return QueryLogDatabaseOutput{
+               ToolName:  "query_log_database",
+               TotalHits: 152,
+               Logs: []LogEntry{
+                       {
+                               Timestamp: "2025-08-16T15:32:05Z",
+                               Level:     "WARN",
+                               Message:   "Timeout waiting for idle object in 
database connection pool.",
+                       },
+                       {
+                               Timestamp: "2025-08-16T15:32:08Z",
+                               Level:     "WARN",
+                               Message:   "Timeout waiting for idle object in 
database connection pool.",
+                       },
+               },
+               Summary: fmt.Sprintf("在过去%d分钟内,发现 152 条关于 '%s' 的日志条目", 
input.TimeRangeMinutes, input.Keyword),
+       }, nil
+}
+
+// ================================================
+// Search Archived Logs Tool
+// ================================================
+
+type SearchArchivedLogsInput struct {
+       FilePathPattern string `json:"filePathPattern" 
jsonschema:"required,description=File path pattern to search"`
+       GrepKeyword     string `json:"grepKeyword" 
jsonschema:"required,description=Keyword to grep for"`
+}
+
+type MatchingLine struct {
+       FilePath    string `json:"filePath"`
+       LineNumber  int    `json:"lineNumber"`
+       LineContent string `json:"lineContent"`
+}
+
+type SearchArchivedLogsOutput struct {
+       ToolName      string         `json:"toolName"`
+       FilesSearched int            `json:"filesSearched"`
+       MatchingLines []MatchingLine `json:"matchingLines"`
+       Summary       string         `json:"summary"`
+}
+
+func (o SearchArchivedLogsOutput) Tool() string {
+       return o.ToolName
+}
+
+func searchArchivedLogs(ctx *ai.ToolContext, input SearchArchivedLogsInput) 
(SearchArchivedLogsOutput, error) {
+       log.Printf("Tool 'search_archived_logs' called with pattern: %s, 
keyword: %s", input.FilePathPattern, input.GrepKeyword)
+
+       return SearchArchivedLogsOutput{
+               ToolName:      "search_archived_logs",
+               FilesSearched: 5,
+               MatchingLines: []MatchingLine{
+                       {
+                               FilePath:    
"/logs/mysql-orders-db/slow-query-2025-08-16.log.gz",
+                               LineNumber:  1024,
+                               LineContent: "Query_time: 25.3s | SELECT 
COUNT(id), SUM(price) FROM orders WHERE user_id = 'VIP_USER_123';",
+                       },
+                       {
+                               FilePath:    
"/logs/mysql-orders-db/slow-query-2025-08-16.log.gz",
+                               LineNumber:  1029,
+                               LineContent: "Query_time: 28.1s | SELECT 
COUNT(id), SUM(price) FROM orders WHERE user_id = 'VIP_USER_456';",
+                       },
+               },
+               Summary: "在归档的日志文件中,发现了多条查询,搜索了 5 个文件,找到了 2 条匹配行",
+       }, nil
+}
+
+// ================================================
+// Query Knowledge Base Tool
+// ================================================
+
+type QueryKnowledgeBaseInput struct {
+       QueryText string `json:"queryText" 
jsonschema:"required,description=Query text to search for"`
+}
+
+type KnowledgeDocument struct {
+       Source          string  `json:"source"`
+       ContentSnippet  string  `json:"contentSnippet"`
+       SimilarityScore float64 `json:"similarityScore"`
+}
+
+type QueryKnowledgeBaseOutput struct {
+       ToolName  string              `json:"toolName"`
+       Documents []KnowledgeDocument `json:"documents"`
+}
+
+func (o QueryKnowledgeBaseOutput) Tool() string {
+       return o.ToolName
+}
+
+func queryKnowledgeBase(ctx *ai.ToolContext, input QueryKnowledgeBaseInput) 
(QueryKnowledgeBaseOutput, error) {
+       log.Printf("Tool 'query_knowledge_base' called with query: %s", 
input.QueryText)
+
+       return QueryKnowledgeBaseOutput{
+               ToolName: "query_knowledge_base",
+               Documents: []KnowledgeDocument{
+                       {
+                               Source:          
"Project-VIP-Feature-Design-Doc.md",
+                               ContentSnippet:  "The 'Lifetime Achievement' 
badge requires calculating total user spending. Note: This may cause slow 
queries on the orders table if the user_id column is not properly indexed.",
+                               SimilarityScore: 0.92,
+                       },
+               },
+       }, nil
+}
+
+// ================================================
+// Tool Registration Function
+// ================================================
+
+var registeredTools []ai.Tool
+
+// RegisterAllMockTools registers all mock diagnostic tools with the genkit 
instance
+func RegisterAllMockTools(g *genkit.Genkit) {
+       registeredTools = []ai.Tool{
+               genkit.DefineTool(g, "prometheus_query_service_latency", 
"查询指定服务在特定时间范围内的 P95/P99 延迟指标", prometheusQueryServiceLatency),
+               genkit.DefineTool(g, "prometheus_query_service_traffic", 
"查询指定服务在特定时间范围内的请求率 (QPS) 和错误率 (Error Rate)", prometheusQueryServiceTraffic),
+               genkit.DefineTool(g, "query_timeseries_database", "执行一条完整的 
PromQL 查询语句,用于进行普罗米修斯历史数据的深度或自定义分析", queryTimeseriesDatabase),
+               genkit.DefineTool(g, "application_performance_profiling", 
"对指定服务的指定实例(Pod)进行性能剖析,以结构化文本格式返回消耗CPU最多的函数调用栈", 
applicationPerformanceProfiling),
+               genkit.DefineTool(g, "jvm_performance_analysis", 
"检查指定Java服务的JVM状态,特别是GC(垃圾回收)活动", jvmPerformanceAnalysis),
+               genkit.DefineTool(g, "trace_dependency_view", 
"基于链路追踪数据,查询指定服务的上下游依赖关系", traceDependencyView),
+               genkit.DefineTool(g, "trace_latency_analysis", 
"分析指定服务在某时间范围内的链路追踪数据,定位延迟最高的下游调用", traceLatencyAnalysis),
+               genkit.DefineTool(g, "database_connection_pool_analysis", 
"查询指定服务连接数据库的连接池状态", databaseConnectionPoolAnalysis),
+               genkit.DefineTool(g, "kubernetes_get_pod_resources", "使用类似 
kubectl 的功能,获取指定服务所有Pod的CPU和内存的静态配置(Limits/Requests)和动态使用情况", 
kubernetesGetPodResources),
+               genkit.DefineTool(g, "dubbo_service_status", "使用类似 dubbo-admin 
的命令,查询指定Dubbo服务的提供者和消费者列表及其状态", dubboServiceStatus),
+               genkit.DefineTool(g, "query_log_database", 
"查询已索引的日志数据库(如Elasticsearch, Loki),用于实时或近实时的日志分析", queryLogDatabase),
+               genkit.DefineTool(g, "search_archived_logs", 
"在归档的日志文件(如存储在S3或服务器文件系统的.log.gz文件)中进行文本搜索(类似grep)", searchArchivedLogs),
+               genkit.DefineTool(g, "query_knowledge_base", 
"在向量数据库中查询与问题相关的历史故障报告或解决方案文档", queryKnowledgeBase),
+       }
+
+       log.Printf("Registered %d mock diagnostic tools", len(registeredTools))
+}
+
+func AllMockToolRef() (toolRef []ai.ToolRef, err error) {
+       if registeredTools == nil {
+               return nil, fmt.Errorf("no mock tools registered")
+       }
+       for _, tool := range registeredTools {
+               toolRef = append(toolRef, tool)
+       }
+       return toolRef, nil
+}
+
+func AllMockToolNames() (toolNames map[string]struct{}, err error) {
+       if registeredTools == nil {
+               return nil, fmt.Errorf("no mock tools registered")
+       }
+       toolNames = make(map[string]struct{})
+       for _, tool := range registeredTools {
+               toolNames[tool.Name()] = struct{}{}
+       }
+       return toolNames, nil
+}
+
+func MockToolRefByNames(names []string) (toolRefs []ai.ToolRef) {
+       for _, name := range names {
+               for _, tool := range registeredTools {
+                       if tool.Name() == name {
+                               toolRefs = append(toolRefs, tool)
+                       }
+               }
+       }
+       return toolRefs
+}
diff --git a/ai/internal/tools/tools.go b/ai/internal/tools/tools.go
new file mode 100644
index 00000000..17a7bded
--- /dev/null
+++ b/ai/internal/tools/tools.go
@@ -0,0 +1,39 @@
+package tools
+
+import (
+       "context"
+       "encoding/json"
+       "fmt"
+
+       "github.com/firebase/genkit/go/genkit"
+)
+
+// type ToolOut interface {
+//     FromRaw(any) ToolOutput
+//     Output() string
+// }
+
+// func (s StringOutput) Output() string {
+//     return s.value
+// }
+
+// ToolDesc 表示要执行的工具调用信息
+type ToolDesc struct {
+       ToolName  string         `json:"tool_name"`
+       ToolInput map[string]any `json:"tool_input"`
+}
+
+func (toolDesc ToolDesc) Call(g *genkit.Genkit, ctx context.Context) (string, 
error) {
+       tool := genkit.LookupTool(g, toolDesc.ToolName)
+       if tool == nil {
+               return "", fmt.Errorf("tool not found: %s", toolDesc.ToolName)
+       }
+
+       rawToolOutput, err := tool.RunRaw(ctx, toolDesc.ToolInput)
+       if err != nil {
+               return "", fmt.Errorf("failed to call tool %s: %w", 
toolDesc.ToolName, err)
+       }
+
+       jsonOutput, err := json.Marshal(rawToolOutput)
+       return string(jsonOutput), err
+}
diff --git a/ai/main.go b/ai/main.go
new file mode 100644
index 00000000..9177148b
--- /dev/null
+++ b/ai/main.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+       "dubbo-admin-ai/internal/agent"
+       "dubbo-admin-ai/plugins/dashscope"
+)
+
+func main() {
+       if err := agent.InitAgent(dashscope.Qwen3); err != nil {
+               panic(err)
+       }
+       select {}
+}
diff --git a/ai/plugins/dashscope/dashscope.go 
b/ai/plugins/dashscope/dashscope.go
new file mode 100644
index 00000000..df838530
--- /dev/null
+++ b/ai/plugins/dashscope/dashscope.go
@@ -0,0 +1,148 @@
+package dashscope
+
+import (
+       "context"
+       "fmt"
+       "os"
+
+       "github.com/firebase/genkit/go/ai"
+       "github.com/firebase/genkit/go/core"
+       "github.com/firebase/genkit/go/genkit"
+       "github.com/firebase/genkit/go/plugins/compat_oai"
+       "github.com/openai/openai-go/option"
+)
+
+const provider = "dashscope"
+const baseURL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
+
+const (
+       qwen3_235b_a22b = "qwen3-235b-a22b-instruct-2507"
+       qwen_max        = "qwen-max"
+       qwen_plus       = "qwen-plus"
+       qwen_flash      = "qwen-flash"
+       qwen3_coder     = "qwen3-coder-plus"
+
+       Qwen3       = provider + "/" + qwen3_235b_a22b
+       Qwen_plus   = provider + "/" + qwen_plus
+       Qwen_max    = provider + "/" + qwen_max
+       Qwen3_coder = provider + "/" + qwen3_coder
+       Qwen_flash  = provider + "/" + qwen_flash
+)
+
+var (
+       supportedModels = map[string]ai.ModelInfo{
+               qwen3_235b_a22b: {
+                       Label:    "qwen3-235b-a22b-instruct-2507",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"qwen3-235b-a22b-instruct-2507"},
+               },
+               qwen_plus: {
+                       Label:    "qwen-plus",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"qwen-plus"},
+               },
+               qwen_max: {
+                       Label:    "qwen-max",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"qwen-max"},
+               },
+               qwen3_coder: {
+                       Label:    "qwen3-coder",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"qwen3-coder"},
+               },
+               qwen_flash: {
+                       Label:    "qwen-flash",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"qwen-flash"},
+               },
+       }
+
+       knownEmbedders = []string{}
+)
+
+type DashScope struct {
+       APIKey string
+
+       Opts []option.RequestOption
+
+       openAICompatible *compat_oai.OpenAICompatible
+}
+
+// Name implements genkit.Plugin.
+func (o *DashScope) Name() string {
+       return provider
+}
+
+// Init implements genkit.Plugin.
+func (o *DashScope) Init(ctx context.Context, g *genkit.Genkit) error {
+       apiKey := o.APIKey
+
+       // if api key is not set, get it from environment variable
+       if apiKey == "" {
+               apiKey = os.Getenv("DASHSCOPE_API_KEY")
+       }
+
+       if apiKey == "" {
+               return fmt.Errorf("DashScope plugin initialization failed: 
apiKey is required")
+       }
+
+       if o.openAICompatible == nil {
+               o.openAICompatible = &compat_oai.OpenAICompatible{}
+       }
+
+       // set the options
+       o.openAICompatible.Opts = []option.RequestOption{
+               option.WithAPIKey(apiKey),
+               option.WithBaseURL(baseURL),
+       }
+
+       if len(o.Opts) > 0 {
+               o.openAICompatible.Opts = append(o.openAICompatible.Opts, 
o.Opts...)
+       }
+
+       o.openAICompatible.Provider = provider
+       if err := o.openAICompatible.Init(ctx, g); err != nil {
+               return err
+       }
+
+       // define default models
+       for model, info := range supportedModels {
+               if _, err := o.DefineModel(g, model, info); err != nil {
+                       return err
+               }
+       }
+
+       // define default embedders
+       for _, embedder := range knownEmbedders {
+               if _, err := o.DefineEmbedder(g, embedder); err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (o *DashScope) Model(g *genkit.Genkit, name string) ai.Model {
+       return o.openAICompatible.Model(g, name, provider)
+}
+
+func (o *DashScope) DefineModel(g *genkit.Genkit, name string, info 
ai.ModelInfo) (ai.Model, error) {
+       return o.openAICompatible.DefineModel(g, provider, name, info)
+}
+
+func (o *DashScope) DefineEmbedder(g *genkit.Genkit, name string) 
(ai.Embedder, error) {
+       return o.openAICompatible.DefineEmbedder(g, provider, name)
+}
+
+func (o *DashScope) Embedder(g *genkit.Genkit, name string) ai.Embedder {
+       return o.openAICompatible.Embedder(g, name, provider)
+}
+
+func (o *DashScope) ListActions(ctx context.Context) []core.ActionDesc {
+       return o.openAICompatible.ListActions(ctx)
+}
+
+func (o *DashScope) ResolveAction(g *genkit.Genkit, atype core.ActionType, 
name string) error {
+       return o.openAICompatible.ResolveAction(g, atype, name)
+}
diff --git a/ai/plugins/siliconflow/siliconflow.go 
b/ai/plugins/siliconflow/siliconflow.go
new file mode 100644
index 00000000..00597baf
--- /dev/null
+++ b/ai/plugins/siliconflow/siliconflow.go
@@ -0,0 +1,141 @@
+package siliconflow
+
+import (
+       "context"
+       "fmt"
+       "os"
+
+       "github.com/firebase/genkit/go/ai"
+       "github.com/firebase/genkit/go/core"
+       "github.com/firebase/genkit/go/genkit"
+       "github.com/firebase/genkit/go/plugins/compat_oai"
+       "github.com/openai/openai-go/option"
+)
+
+const provider = "siliconflow"
+const baseURL = "https://api.siliconflow.cn/v1";
+
+const (
+       deepseekV3 = "deepseek-ai/DeepSeek-V3"
+       deepseekR1 = "deepseek-ai/DeepSeek-R1"
+       qwenQwQ32B = "Qwen/QwQ-32B"
+       qwen3Coder = "Qwen/Qwen3-Coder-480B-A35B-Instruct"
+
+       DeepSeekV3 = provider + "/" + deepseekV3
+       QwenQwQ32B = provider + "/" + qwenQwQ32B
+       Qwen3Coder = provider + "/" + qwen3Coder
+       DeepSeekR1 = provider + "/" + deepseekR1
+)
+
+var (
+       supportedModels = map[string]ai.ModelInfo{
+               deepseekV3: {
+                       Label:    "deepseek-ai/DeepSeek-V3",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"DeepSeek-V3-0324"},
+               },
+               qwen3Coder: {
+                       Label:    "Qwen/Qwen3-Coder-480B-A35B-Instruct",
+                       Supports: &compat_oai.Multimodal,
+                       Versions: []string{"Qwen3-Coder-480B-A35B"},
+               },
+               qwenQwQ32B: {
+                       Label:    "Qwen/QwQ-32B",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"QwQ-32B"},
+               },
+               deepseekR1: {
+                       Label:    "deepseek-ai/DeepSeek-R1",
+                       Supports: &compat_oai.BasicText,
+                       Versions: []string{"DeepSeek-R1-0528"},
+               },
+       }
+
+       knownEmbedders = []string{}
+)
+
+type SiliconFlow struct {
+       APIKey string
+
+       Opts []option.RequestOption
+
+       openAICompatible *compat_oai.OpenAICompatible
+}
+
+// Name implements genkit.Plugin.
+func (o *SiliconFlow) Name() string {
+       return provider
+}
+
+// Init implements genkit.Plugin.
+func (o *SiliconFlow) Init(ctx context.Context, g *genkit.Genkit) error {
+       apiKey := o.APIKey
+
+       // if api key is not set, get it from environment variable
+       if apiKey == "" {
+               apiKey = os.Getenv("SILICONFLOW_API_KEY")
+       }
+
+       if apiKey == "" {
+               return fmt.Errorf("siliconflow plugin initialization failed: 
apiKey is required")
+       }
+
+       if o.openAICompatible == nil {
+               o.openAICompatible = &compat_oai.OpenAICompatible{}
+       }
+
+       // set the options
+       o.openAICompatible.Opts = []option.RequestOption{
+               option.WithAPIKey(apiKey),
+               option.WithBaseURL(baseURL),
+       }
+
+       if len(o.Opts) > 0 {
+               o.openAICompatible.Opts = append(o.openAICompatible.Opts, 
o.Opts...)
+       }
+
+       o.openAICompatible.Provider = provider
+       if err := o.openAICompatible.Init(ctx, g); err != nil {
+               return err
+       }
+
+       // define default models
+       for model, info := range supportedModels {
+               if _, err := o.DefineModel(g, model, info); err != nil {
+                       return err
+               }
+       }
+
+       // define default embedders
+       for _, embedder := range knownEmbedders {
+               if _, err := o.DefineEmbedder(g, embedder); err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (o *SiliconFlow) Model(g *genkit.Genkit, name string) ai.Model {
+       return o.openAICompatible.Model(g, name, provider)
+}
+
+func (o *SiliconFlow) DefineModel(g *genkit.Genkit, name string, info 
ai.ModelInfo) (ai.Model, error) {
+       return o.openAICompatible.DefineModel(g, provider, name, info)
+}
+
+func (o *SiliconFlow) DefineEmbedder(g *genkit.Genkit, name string) 
(ai.Embedder, error) {
+       return o.openAICompatible.DefineEmbedder(g, provider, name)
+}
+
+func (o *SiliconFlow) Embedder(g *genkit.Genkit, name string) ai.Embedder {
+       return o.openAICompatible.Embedder(g, name, provider)
+}
+
+func (o *SiliconFlow) ListActions(ctx context.Context) []core.ActionDesc {
+       return o.openAICompatible.ListActions(ctx)
+}
+
+func (o *SiliconFlow) ResolveAction(g *genkit.Genkit, atype core.ActionType, 
name string) error {
+       return o.openAICompatible.ResolveAction(g, atype, name)
+}
diff --git a/ai/prompts/agentSystem.prompt b/ai/prompts/agentSystem.prompt
new file mode 100644
index 00000000..b5509ff6
--- /dev/null
+++ b/ai/prompts/agentSystem.prompt
@@ -0,0 +1,90 @@
+# 1. 角色设定 (Persona)
+You are "Dubbot", the **reasoning brain** of a ReAct (Reasoning and Acting) 
agent system. You are an expert Site Reliability Engineer (SRE) and 
observability specialist integrated within the Dubbo Admin control plane. Your 
sole responsibility is **thinking and decision-making** - you analyze 
information, reason about problems, and decide what actions should be taken 
next.
+
+You do NOT execute tools or actions yourself. You are the strategic thinker 
who guides the problem-solving process.
+
+# 2. ReAct 核心流程 (ReAct Core Process)
+You operate within the **ReAct paradigm**: **Reasoning → Acting → Observing → 
Reasoning...**
+
+**Your role in this cycle:**
+1. **THOUGHT (思考)**: Analyze current information and reason about the problem
+2. **DECISION (决策)**: Decide what actions/tools should be executed next (can 
be multiple parallel tools for efficiency), or if enough information exists to 
provide a final answer
+3. **ITERATION (迭代)**: Continue this cycle until the problem is fully diagnosed
+
+**You receive**: User questions + Historical observations from previous tool 
executions
+**You output**: Your reasoning process + Next action decision OR final 
diagnosis
+
+# 3. ReAct 思维框架 (ReAct Thinking Framework)
+For each reasoning cycle, follow this structured approach:
+
+## **Step 1: 状态分析 (State Analysis)**
+- What do I know so far from the user question and previous observations?
+- What patterns or anomalies have been identified?
+- What hypotheses have been formed or ruled out?
+
+## **Step 2: 问题分解 (Problem Decomposition)**
+- What are the possible root causes for this issue?
+- What aspects of the system need to be investigated?
+- Which investigation path is most likely to yield useful information?
+
+## **Step 3: 信息差距识别 (Information Gap Analysis)**
+- What critical information am I still missing?
+- Which data points would help confirm or refute my hypotheses?
+- What independent information sources can be queried in parallel for 
efficiency?
+- What is the most efficient approach to gather needed information (single vs 
multiple tools)?
+
+## **Step 4: 行动决策 (Action Decision)**
+- Should I gather more data (status="CONTINUED") or provide final answer 
(status="FINISHED")?
+- If gathering data: Which specific tools should be used and with what 
parameters?
+- Can multiple tools be executed in parallel to improve efficiency (no data 
dependencies)?
+- If final answer: Do I have sufficient evidence to make a confident diagnosis?
+
+# 4. 可用工具与数据源 (Available Tools & Data Sources)
+You can request data from these sources through tool calls:
+- **Metrics Tools**: Performance indicators (latency, QPS, error rates, 
resource usage)
+- **Logging Tools**: Application logs from all services (INFO, WARN, ERROR 
levels)
+- **Tracing Tools**: Distributed traces showing request lifecycle across 
services
+- **Metadata Tools**: Service dependencies, instance information, 
configurations
+- **Knowledge Base Tools**: Historical incidents, troubleshooting guides, best 
practices
+
+## 并行工具执行原则 (Parallel Tool Execution Guidelines)
+**Execute multiple tools in parallel when:**
+- Information sources are independent (no data dependencies between tools)
+- Different aspects of the system need investigation simultaneously
+- Multiple hypotheses can be validated concurrently
+- Efficiency gains outweigh coordination complexity
+
+**Use single tool execution when:**
+- Results from one tool determine parameters for the next tool
+- Sequential analysis is required (e.g., trace analysis → log filtering)
+- System resources are limited or tools have mutual exclusion requirements
+
+# 5. 输出决策逻辑 (Output Decision Logic)
+**Continue Investigating (status="CONTINUED")** when:
+- Key information is missing for diagnosis
+- Multiple hypotheses need validation (consider parallel tool execution)
+- Current evidence is insufficient or contradictory
+- Independent data sources can be queried simultaneously for efficiency
+
+**Provide Final Answer (status="FINISHED")** when:
+- Root cause is clearly identified with supporting evidence
+- Sufficient data has been gathered to make confident diagnosis
+- Clear troubleshooting steps can be recommended
+
+**Important**: final_answer field must always be a string type:
+- When there is a final answer: Provide specific diagnosis and recommendation 
content
+- When there is no final answer: Use empty string "" (do not use null)
+
+# 6. ReAct 思考要求 (ReAct Thinking Requirements)
+1. **Be Systematic**: Follow the thinking framework step by step
+2. **Be Evidence-Based**: Ground all reasoning in observed data
+3. **Be Iterative**: Treat each cycle as building upon previous observations
+4. **Be Strategic**: Choose the most informative actions (single or multiple 
tools as appropriate)
+5. **Be Efficient**: Prefer parallel tool execution when data sources are 
independent
+6. **Be Decisive**: Know when you have enough information to conclude
+
+**Your output MUST be a single valid JSON object following the specified 
schema.**
+
+**Field Type Requirements**: All string fields must be valid strings, never 
use null values. Use empty string "" for final_answer when no content.
+
+**Remember: You are the BRAIN of the ReAct agent. Think deeply, reason 
carefully, and guide the investigation process strategically.**
\ No newline at end of file
diff --git a/ai/prompts/menuPrompt.prompt b/ai/prompts/menuPrompt.prompt
new file mode 100644
index 00000000..61faf580
--- /dev/null
+++ b/ai/prompts/menuPrompt.prompt
@@ -0,0 +1,15 @@
+---
+input:
+  schema:
+    theme?: string
+  default:
+    theme: "pirate"
+output:
+  schema:
+    dishname: string
+    description: string
+    calories: integer
+    allergens(array): string
+---
+Invent a menu item for a {{theme}} themed
+restaurant.
\ No newline at end of file
diff --git a/ai/prompts/weatherPrompt.prompt b/ai/prompts/weatherPrompt.prompt
new file mode 100644
index 00000000..105ed3a4
--- /dev/null
+++ b/ai/prompts/weatherPrompt.prompt
@@ -0,0 +1,12 @@
+---
+system: "Answer questions using the tools you have."
+tools: [getWeather]
+input:
+  schema:
+    location: string
+output:
+  schema:
+    type: string
+---
+
+What is the weather in {{location}}?
\ No newline at end of file
diff --git a/ai/test/flow_test.go b/ai/test/flow_test.go
new file mode 100644
index 00000000..39c6c3b6
--- /dev/null
+++ b/ai/test/flow_test.go
@@ -0,0 +1,107 @@
+package test
+
+import (
+       "context"
+       "dubbo-admin-ai/internal/agent"
+       "dubbo-admin-ai/internal/schema"
+       "encoding/json"
+       "fmt"
+       "testing"
+)
+
+func TestThinking(t *testing.T) {
+       ctx := context.Background()
+       agentInput := schema.ReActInput{
+               UserInput: "我的微服务 order-service 运行缓慢,请帮助我诊断原因",
+       }
+
+       resp, err := agent.ThinkingFlow.Run(ctx, agentInput)
+       if err != nil {
+               t.Fatalf("failed to run thinking flow: %v", err)
+       }
+       if resp == nil {
+               t.Fatal("expected non-nil response")
+       }
+
+       fmt.Print(resp)
+}
+
+func TestAct(t *testing.T) {
+       ctx := context.Background()
+
+       actInJson := `{
+  "tool_requests": [
+    {
+      "thought": "查询order-service的P95和P99延迟指标,以确认性能问题的严重程度。",
+      "tool_desc": {
+        "tool_name": "prometheus_query_service_latency",
+        "tool_input": {
+          "quantile": 0.95,
+          "serviceName": "order-service",
+          "timeRangeMinutes": 10
+        }
+      }
+    },
+    {
+      "thought": "查询order-service的QPS和错误率,评估服务负载和健康状态。",
+      "tool_desc": {
+        "tool_name": "prometheus_query_service_traffic",
+        "tool_input": {
+          "serviceName": "order-service",
+          "timeRangeMinutes": 10
+        }
+      }
+    },
+    {
+      "thought": "分析order-service的链路追踪数据,找出延迟最高的下游调用。",
+      "tool_desc": {
+        "tool_name": "trace_latency_analysis",
+        "tool_input": {
+          "serviceName": "order-service",
+          "timeRangeMinutes": 10
+        }
+      }
+    },
+    {
+      "thought": "检查order-service的Dubbo提供者和消费者列表及其状态,确认服务依赖是否正常。",
+      "tool_desc": {
+        "tool_name": "dubbo_service_status",
+        "tool_input": {
+          "serviceName": "order-service"
+        }
+      }
+    }
+  ],
+  "status": "CONTINUED",
+  "thought": 
"初步分析表明order-service的性能问题可能有多个潜在原因,包括高延迟的下游调用、资源不足、JVM问题或数据库连接池问题等。首先需要收集系统性能数据,以便进一步诊断。"
+}`
+       actIn := &schema.ThinkAggregation{}
+       if err := json.Unmarshal([]byte(actInJson), actIn); err != nil {
+               t.Fatalf("failed to unmarshal actInJson: %v", err)
+       }
+
+       resp, err := agent.ActFlow.Run(ctx, actIn)
+       if err != nil {
+               t.Fatalf("failed to run act flow: %v", err)
+       }
+       if resp == nil {
+               t.Fatal("expected non-nil response")
+       }
+
+       for _, r := range resp {
+               fmt.Println(r)
+       }
+}
+
+func TestReAct(t *testing.T) {
+       ctx := context.Background()
+       agentInput := schema.ReActInput{
+               UserInput: "我的微服务 order-service 运行缓慢,请帮助我诊断原因",
+       }
+
+       reActResp, err := agent.ReActFlow.Run(ctx, agentInput)
+       if err != nil {
+               t.Fatalf("failed to run reAct flow: %v", err)
+       }
+       fmt.Println(reActResp)
+}
diff --git a/ai/test/llm_test.go b/ai/test/llm_test.go
new file mode 100644
index 00000000..b2081eaa
--- /dev/null
+++ b/ai/test/llm_test.go
@@ -0,0 +1,66 @@
+package test
+
+import (
+       "context"
+       "dubbo-admin-ai/internal/manager"
+       "fmt"
+       "log"
+       "testing"
+
+       "github.com/firebase/genkit/go/ai"
+       "github.com/firebase/genkit/go/core"
+       "github.com/firebase/genkit/go/genkit"
+)
+
+type WeatherInput struct {
+       Location string `json:"location" jsonschema_description:"Location to 
get weather for"`
+}
+
+func defineWeatherFlow(g *genkit.Genkit) *core.Flow[WeatherInput, string, 
struct{}] {
+       getWeatherTool := genkit.DefineTool(g, "getWeather", "Gets the current 
weather in a given location",
+               func(ctx *ai.ToolContext, input WeatherInput) (string, error) {
+                       // Here, we would typically make an API call or 
database query. For this
+                       // example, we just return a fixed value.
+                       log.Printf("Tool 'getWeather' called for location: %s", 
input.Location)
+                       return fmt.Sprintf("The current weather in %s is 63°F 
and sunny.", input.Location), nil
+               })
+
+       return genkit.DefineFlow(g, "getWeatherFlow",
+               func(ctx context.Context, location WeatherInput) (string, 
error) {
+                       resp, err := genkit.Generate(ctx, g,
+                               ai.WithTools(getWeatherTool),
+                               ai.WithPrompt("What's the weather in %s?", 
location.Location),
+                       )
+                       if err != nil {
+                               return "", err
+                       }
+                       return resp.Text(), nil
+               })
+}
+
+func TestTextGeneration(t *testing.T) {
+       ctx := context.Background()
+       g, err := manager.GetGlobalGenkit()
+       if err != nil {
+               t.Fatalf("failed to initialize genkit: %v", err)
+       }
+
+       resp, err := genkit.GenerateText(ctx, g, ai.WithPrompt("Hello, Who are 
you?"))
+       if err != nil {
+               t.Fatalf("failed to generate text: %v", err)
+       }
+       t.Logf("Generated text: %s", resp)
+
+       fmt.Printf("%s", resp)
+}
+
+func TestWeatherFlowRun(t *testing.T) {
+       ctx := context.Background()
+       g, err := manager.GetGlobalGenkit()
+       if err != nil {
+               t.Fatalf("failed to initialize genkit: %v", err)
+       }
+
+       flow := defineWeatherFlow(g)
+       flow.Run(ctx, WeatherInput{Location: "San Francisco"})
+}
diff --git a/ai/test/test.go b/ai/test/test.go
new file mode 100644
index 00000000..2e302f44
--- /dev/null
+++ b/ai/test/test.go
@@ -0,0 +1,12 @@
+package test
+
+import (
+       "dubbo-admin-ai/internal/agent"
+       "dubbo-admin-ai/plugins/dashscope"
+)
+
+func init() {
+       if err := agent.InitAgent(dashscope.Qwen3); err != nil {
+               panic(err)
+       }
+}
diff --git a/ai/utils/utils.go b/ai/utils/utils.go
new file mode 100644
index 00000000..03ecc837
--- /dev/null
+++ b/ai/utils/utils.go
@@ -0,0 +1,52 @@
+package utils
+
+import (
+       "fmt"
+       "io"
+       "os"
+       "path/filepath"
+)
+
+// CopyFile 复制源文件内容到目标文件,如果目标文件不存在,则会创建该文件
+// srcPath: 源文件路径
+// dstPath: 目标文件路径
+func CopyFile(srcPath, dstPath string) error {
+       // 打开源文件
+       srcFile, err := os.Open(srcPath)
+       if err != nil {
+               return fmt.Errorf("failed to open source file %s: %w", srcPath, 
err)
+       }
+       defer srcFile.Close()
+
+       // 获取源文件信息
+       srcInfo, err := srcFile.Stat()
+       if err != nil {
+               return fmt.Errorf("failed to get source file info %s: %w", 
srcPath, err)
+       }
+
+       // 确保目标目录存在
+       dstDir := filepath.Dir(dstPath)
+       if err := os.MkdirAll(dstDir, 0755); err != nil {
+               return fmt.Errorf("failed to create target directory %s: %w", 
dstDir, err)
+       }
+
+       // 创建或覆盖目标文件
+       dstFile, err := os.Create(dstPath)
+       if err != nil {
+               return fmt.Errorf("failed to create target file %s: %w", 
dstPath, err)
+       }
+       defer dstFile.Close()
+
+       // 复制文件内容
+       _, err = io.Copy(dstFile, srcFile)
+       if err != nil {
+               return fmt.Errorf("failed to copy file content: %w", err)
+       }
+
+       // 设置目标文件权限与源文件相同
+       if err := os.Chmod(dstPath, srcInfo.Mode()); err != nil {
+               return fmt.Errorf("failed to set file permissions: %w", err)
+       }
+
+       return nil
+}

Reply via email to