apiKey: sk-xxxxxxxxxxxxxxxxxxxxxxx
domain: dashscope.aliyuncs.com
serviceName: dashscope
servicePort: 443
promptTemplate:
language: CH
apis:
- apiProvider:
domain: restapi.amap.com
serviceName: geo
servicePort: 80
apiKey:
in: query
name: key
value: fcxxxxxxxxxxxxxxxxxx
api: |
openapi: 3.1.0
info:
title: 高德地圖
description: 獲取 POI 的相關信息
version: v1.0.0
servers:
- url: https://restapi.amap.com
paths:
/v5/place/text:
get:
description: 根據POI名稱,獲得POI的經緯度坐標
operationId: get_location_coordinate
parameters:
- name: keywords
in: query
description: POI名稱,必須是中文
required: true
schema:
type: string
- name: region
in: query
description: POI所在的區域名,必須是中文
required: true
schema:
type: string
deprecated: false
/v5/place/around:
get:
description: 搜索給定坐標附近的POI
operationId: search_nearby_pois
parameters:
- name: keywords
in: query
description: 目標POI的關鍵字
required: true
schema:
type: string
- name: location
in: query
description: 中心點的經度和緯度,用逗號隔開
required: true
schema:
type: string
deprecated: false
components:
schemas: {}
- apiProvider:
domain: api.seniverse.com
serviceName: seniverse
servicePort: 80
apiKey:
in: query
name: key
value: SMxxxxxxxxxxxxxx
api: |
openapi: 3.1.0
info:
title: 心知天氣
description: 獲取 天氣預辦相關信息
version: v1.0.0
servers:
- url: https://api.seniverse.com
paths:
/v3/weather/now.json:
get:
description: 獲取指定城市的天氣實況
operationId: get_weather_now
parameters:
- name: location
in: query
description: 所查詢的城市
required: true
schema:
type: string
- name: language
in: query
description: 返回天氣查詢結果所使用的語言
required: true
schema:
type: string
default: zh-Hans
enum:
- zh-Hans
- en
- ja
- name: unit
in: query
description: 表示溫度的的單位,有攝氏度和華氏度兩種
required: true
schema:
type: string
default: c
enum:
- c
- f
deprecated: false
components:
schemas: {}

插件配置分三部分,第一部分dashscope,是通義千問大模型服務的相關信息,第二部分promptTemplate,是自定義agent react模板的配置項,示例中的language是指使用中文模板,第三部分apis是外部API服務的相關配置,包含服務相關信息apiProvider以及api(tools)的OpenAPI文檔,這一部分是實現agent調用外部工具的關鍵,agent會通過理解OpenAPI文檔來理解參數應該賦什么值。

插件效果

示例請求一:Terminal window

curl 'http://<這里換成網關公網IP>/api/openai/v1/chat/completions' \-H 'Accept: application/json, text/event-stream' \-H 'Content-Type: application/json' \--data-raw '{"messages":[{"role":"user","content":"我想在濟南市鑫盛大廈附近喝咖啡,給我推薦幾個"}],"model":"qwen","stream":false}'

示例響應一:

{...,"content":" 在濟南市鑫盛大廈附近,您可以選擇以下咖啡店:\n1. luckin coffee 瑞幸咖啡(鑫盛大廈店),位于新濼大街1299號鑫盛大廈2號樓大堂;\n2. 三慶齊盛廣場挪瓦咖啡(三慶·齊盛廣場店),位于新濼大街與穎秀路交叉口西南60米;\n3. luckin coffee 瑞幸咖啡(三慶·齊盛廣場店),位于穎秀路1267號;\n4. 庫迪咖啡(齊魯軟件園店),位于新濼大街三慶齊盛廣場4號樓底商;\n5. 庫迪咖啡(美蓮廣場店),位于高新區新濼大街1166號美蓮廣場L117號;以及其他一些選項。希望這些建議對您有所幫助!"...}

示例請求二:

curl 'http://<這里換成網關公網IP>/api/openai/v1/chat/completions' \-H 'Accept: application/json, text/event-stream' \-H 'Content-Type: application/json' \--data-raw '{"messages":[{"role":"user","content":"濟南市現在的天氣情況如何?"}],"model":"qwen","stream":false}'

示例響應二:

{..."content":" 濟南市現在的天氣狀況為陰天,溫度為31℃。此信息最后更新于2024年8月9日15時12分(北京時間)。"...}

示例請求三:Terminal window

curl 'http://<這里換成網關公網IP>/api/openai/v1/chat/completions' \-H 'Accept: application/json, text/event-stream' \-H 'Content-Type: application/json' \--data-raw '{"messages":[{"role":"user","content":"濟南市現在的天氣情況如何?用華氏度表示,用日語回答"}],"model":"qwen","stream":false}'

示例響應三:

{..."content":" 濟南市の現在の天気は雨曇りで、気溫は88°Fです。この情報は2024年8月9日15時12分(東京時間)に更新されました。"...}

三、AI Agent實現原理

ReAct原理

AI Agent插件的實現是使用了ReAct(Reasoning and Action),ReAct一詞來自于論文《ReAct: Synergizing Reasoning and Acting in Language Models》,其核心思想是通過思維鏈的方式,引導模型將復雜問題進行拆分,一步一步地推理(Reasoning)和行動(Action),同事還引入了觀察(Observation)環節,在每次執行(Action)之后,都會先觀察(Observation)當前現狀,然后再進行下一步的推理(Reasoning)。
ReAct,就是要讓開發者引導大模型進行推理,然后根據推理結果,判斷需要采取哪個行動(調用工具),與外界環境互動。
ReAct的工作流程如下:
image.png

插件實現邏輯

插件的工作流程如下:
image.png
AI Proxy插件配置在默認階段,而AI Agent可以配置在確保比AI Agent優先級高的階段,比如認證階段。這樣可以保證用戶的http request可以先被AI Agent攔截到。
AI Agent的處理過程分為三個部分。

1. 參數配置

使用AI Agent需要先按上一章節的插件參數配置的格式配置好服務以及api相關參數,也就是圖中第0步要做的工作。

2. prompt模板

首先,因為Agent是一個一步一步思考,多次調用工具的過程,因此是一個多輪對話場景,因此AI Agent維護了一個messageStore,用來存儲歷史對話。
整個Agent ReAct的控制核心就在于prompt模板,中文版本的模板如下:

盡你所能回答以下問題。你可以使用以下工具:{tools}請使用以下格式,其中Action字段后必須跟著Action Input字段,并且不要將Action Input替換成Input或者tool等字段,不能出現格式以外的字段名,每個字段在每個輪次只出現一次:Question: 你需要回答的輸入問題Thought: 你應該總是思考該做什么Action: 要采取的動作,動作只能是{tools_name}中的一個 ,一定不要加入其它內容Action Input: 行動的輸入,必須出現在Action后。Observation: 行動的結果...(這個Thought/Action/Action Input/Observation可以重復N次)Thought: 我現在知道最終答案Final Answer: 對原始輸入問題的最終答案再次重申,不要修改以上模板的字段名稱,開始吧!Question: {input}

該模板指導了大模型的推理過程。
在AI Agent的onHttpRequestBody階段,接收到用戶的query后,例如:我要在北京五道口附近喝咖啡,幫我推薦一下,會將query填入{input}部分,同時將插件參數配置中的api名稱,功能以及OpenAPI文檔放在{tools}部分,將api名稱放在{tools_name}部分。
將該prompt模板存入到messageStore中,格式為:

role: usermsg: {prompt模板}

之后通過proxywasm.ReplaceHttpRequestBody函數用prompt模板替換掉用戶的原始query,通過ai-proxy發送給大模型。
此部分對應圖中的1,2,3,4步驟。

3. 推理過程(工具調用)

大模型的返回會在AI Agent的onHttpResponseBody階段攔截到。此時首先將回復內容存儲到messageStore中,格式為:

role: assistantmsg: {大模型的回復}

之后需要通過正則表達式來判斷大模型的返回內容。
例如上文的例子,大模型會返回如下內容:

Thought: 為了提供咖啡店的推薦,我首先需要獲取五道口這一地點的經緯度坐標。Action: get_location_coordinateAction Input: {"keywords": "五道口", "region": "北京市"}

通過正則表達式取出Action與Action Input的值,就得到了需要調用的工具名稱以及參數的值。
由于通常外部API都會提供一個認證apiKey,只有配置了apiKey,才能使用api接口。以本例子為例,需要在url中包含key={apiKey}的參數,所以我在apiProvider中對apiKey做了設計。包含name和value兩個字段,name表示實際服務商要求的apiKey的名稱,例如本例中的key,value是具體的apiKey值。
程序還會根據OpenAPI文檔拼接處url以及查看method是什么,從而發送對應的http請求,例如本例子是要發送:

GET https://restapi.amap.com/v5/place/text?key=xxxxxx&keywords=五道口&region=北京市

該API的回復為:

{"status":0,"message":"成功","result":{"location":{"lng":116.352978,"lat":39.982849},"precise":1,"confidence":100,"comprehension":100}}

將該回復拼接到Observation后面,作為新的query,在存儲到messageStore后,將整個歷史對話發送給大模型。此時由于處在插件的onHttpResponseBody階段,無法再通過ai-proxy訪問大模型,因此需要自己去調用dashscope client訪問大模型。
大模型會返回如下內容:

Thought: 現在我得到了五道口的經緯度坐標,接下來我可以使用這些坐標來搜索附近的咖啡店。Action: search_nearby_poisAction Input: {"keywords": "咖啡", "longitude": "116.352978", "latitude": "39.982849"}

程序通過正則得到Action與Action Input后,會重復剛才的過程,組裝新的url,向高德地圖發請求,然后把結果存messageStore后給到大模型。整個過程是一個不斷遞歸調用的過程。
大模型會再次返回:

Thought: 我現在知道最終答案Final Answer: 在北京市五道口附近有幾家咖啡店可以選擇,包括:- 星巴克五道口店- Costa Coffee五道口店- 漫咖啡五道口店您可以根據個人喜好選擇前往。

這一次,程序通過可以檢測到回復中包含了Final Answer,這說明大模型已經得到了最終答案,無需再次調用工具了。因此檢測到Final Answer就是結束遞歸調用的條件,此時就可以將Final Answer的答案通過proxywasm.ReplaceHttpResponseBody函數替換掉response body返回給用戶了。
該部分對應圖中的5,6,7,8步驟。

四、總結

本文主要介紹了AI Agent的背景,概念,探討了AI Agent網關插件的使用方法,效果以及實現原理。希望對你有幫助!

插件的實現已經提交PR給Higress開源社區,可以到這里查看完整的代碼實現:https://github.com/alibaba/higress/pull/1192

原文鏈接:https://higress.cn/blog/higress-gvr7dx_awbbpb_im44tpldqyt8c97d/

上一篇:

如何用Python構建與OpenAI API兼容的API?

下一篇:

構建游戲 API 的6個關鍵步驟
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費