把技術選得對,之後每一次需求變動都像換鞋帶,而不是換腳。以下是我在
eap-ai-client
採用的技術棧與背後取捨,聚焦「可維護、可治理」。
在講完我的mcp工具實作後,此篇文章要來介紹我用來串接LLM模型的服務,這個服務初衷是希望我能透過自然語言來對我的eap工具進行操作,像是我可以輸入"請幫我依據現在市場最低賣價,買入20單位的電力"那LLM就會幫我們呼叫mcp工具來進行操作,那也可以使用自然語言來進行整體市場環境的模擬。
action
、toolName
、params
、planVersion
),@NotNull
、@Pattern
)做 Schema 檢核,拒收不合格回覆。@ConfigurationProperties
設定 llm.provider/baseUrl/model/apiKey,由 Profile/配置決定注入哪個 Adapter(OpenAI、Ollama…)。切換供應商=改設定+換 Adapter Bean,不動業務程式。McpToolClient
這個 Port;工具清單或傳輸協定(HTTP → gRPC)變動由底層 Adapter 吸收。ai-service
不管工具實作細節,維持和 LLM 一樣的解耦關係。
ai-service
只負責「理解與下決策」→「呼叫工具」的編排;供應商與工具實作細節都被 Adapter 吃掉,日後要換 LLM 或擴工具,不會牽動核心服務。
McpToolClient
作為 Port,底層以 WebClient/Feign Adapter 實作;getOrderBook
, getMarketMetrics
)直接放行。placeOrder
, cancelOrder
, registerUser
)走確認機制:
AiChatService
檢視 action
→ 3) 未帶「確認旗標」則回要求確認的自然語言 → 4) 收到確認後才呼叫。@ConfigurationProperties
:llm.*
、mcp.*
、resilience.*
一次綁定,避免硬編碼。dev/staging/prod
切換 endpoint、重試策略、模型名稱。UserInputError
(使用者/模型參數不完整)ToolRejectedError
(未經確認或政策禁止)DownstreamError
(MCP 或下游)SystemError
(不可預期)extra
擴充位,避免破壞性變更。toolName
直接拒絕。使用者/系統 → AiChatController → AiChatService
→ ChatClient(LLM)
↘ Plan(JSON) 驗證/正規化
→(Read-only? 直接)
→(State-changing? 要確認)
→ McpToolClient → eap-mcp(工具)→ 下游服務
把上面理念落進程式:application.yml
與 @ConfigurationProperties
的切分、ChatClient/MCP 的 Bean 設計、Resilience4j 與 OTel 的最小實用配置,一鍵換 Provider、不改核心碼。