# 《OpenAI API 開發手冊》服務專區 {%youtube eEqi1Qxc5AE%} - [本書範例檔案](#%E6%9C%AC%E6%9B%B8%E7%AF%84%E4%BE%8B%E6%AA%94%E6%A1%88) - [旗標官網頁面](https://www.flag.com.tw/books/product/F5762) - [勘誤](https://hackmd.io/cixa-XYvSW22UGcz6flVGA#%E5%8B%98%E8%AA%A4) ## 本書範例檔案 ### 第 1 章 - [Colab 筆記本](https://colab.research.google.com/drive/1g2StUAFx5Ev3pKnr7xM66OFHTN0qm4X3?usp=sharing) - [OpenAI API 註冊與申請金鑰流程](https://hackmd.io/@flagmaker/BJuxF7bkye) - [OpenAI Tokenizer 網站](https://platform.openai.com/tokenizer) - [tiktokenizer 網站](https://tiktokenizer.vercel.app/) ### 第 2 章 - [Colab 筆記本](https://colab.research.google.com/drive/1tZhG0mCG4s4S3DbgzqfSZPeEaC3QXvvb?usp=sharing) - [驗證組織的網頁](https://platform.openai.com/settings/organization/general) #### 輸入圖片的計費 計費方式相關資訊: - [輸入圖片的計費方式](https://platform.openai.com/docs/guides/images#calculating-costs) - [Pricing 頁面](https://openai.com/api/pricing/) FAQ 區最後有輸入圖片的費用計算機 - [驗算用的輔助函式](https://colab.research.google.com/drive/15UqEWFWyRKOSnm7UzgplW4pJ7xYV8t29?usp=sharing) ### 第 3 章 - [Colab 筆記本](https://colab.research.google.com/drive/1xREEYvkOMppizk5WorSF_nQU80A-LGrt?usp=sharing) ### 第 4 章 - [Colab 筆記本](https://colab.research.google.com/drive/1EXEpkyxETc1Sn7_2BMdKd6brasmINwDL?usp=sharing) - [搜尋工具的計價方式](https://platform.openai.com/docs/pricing#web-search) - [檔案檢索工具的計費方式](https://platform.openai.com/docs/pricing#built-in-tools) ### 第 5 章 - [Colab 筆記本](https://colab.research.google.com/drive/1GGomc4iwTq3ohX_cx16P5dT1mI0O6MV0?usp=sharing) ### 第 6 章 - [Colab 筆記本](https://colab.research.google.com/drive/1pVisiBOP3iCqWxhXvw_OHUP9NUq-gLvx?usp=sharing) - [最後版本的 Chat 類別](https://colab.research.google.com/drive/1wqyPtoddd7xG-TC3JtNqee6aIJaiIXFc?usp=sharing) ### 第 7 章 - [範例下載](https://github.com/FlagTech/F5762_mcp/archive/refs/heads/master.zip) - [uv 工具教學](https://reurl.cc/YYmamx) - uv 工具安裝: - Windows: ``` powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" ``` - Mac 或是 Linux: ``` curl -LsSf https://astral.sh/uv/install.sh | sh ``` #### 7-2 MCP 伺服器開發 :::info 請記得修改 MCP 伺服器程式檔路徑為你自己專案的路徑。 ::: ##### 測試 MCP 伺服器: ```json { "mcpServers": { "shell_helper": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_shell_helper.py" ] } } } ``` ##### 多個 MCP 伺服器共同運作 ```json { "mcpServers": { "shell_helper": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_shell_helper.py" ] }, "google_search": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_google_search.py" ] } } } ``` #### 7-3 MCP 用戶端 ##### 使用單一 MCP 伺服器的應用程式 ```json { "mcpServers": { "shell_helper": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_shell_helper.py" ] }, } } ``` ##### 同時使用多個 MCP 伺服器 ```json { "mcpServers": { "shell_helper": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_shell_helper.py" ] }, "google_search": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_google_search.py" ] } } } ``` ##### 使用其他人設計的 MCP 伺服器 ```json { "mcpServers": { "shell_helper": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_shell_helper.py" ] }, "google_search": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_google_search.py" ] }, "fetch": { "command": "uvx", "args": ["mcp-server-fetch"] } } } ``` ###### JSON Schema 相容問題 ```json { "mcpServers": { "pan-doc": { "command": "uvx", "args": ["pan-doc"] } } } ``` ### 第 8 章 本章範例與第 7 章是同一個專案,沿用即可。若有需要,再重新下載: - [範例下載](https://github.com/FlagTech/F5762_mcp/archive/refs/heads/master.zip) 本章大部分都是在本機端執行的程式範例,但 8-2 節會使用到單獨的 Colab 筆記本: - [Colab 筆記本](https://colab.research.google.com/drive/1qvaIlGVAZWEITFyW8WbgPYfQgA6dEJmW?usp=sharing) #### 8-1 使用 SSE 將 MCP 伺服器部署在網路上 ##### 使用 SSE 傳輸的 MCP 用戶端: ```json { "mcpServers": { "sse_google_search": { "url": "http://localhost:8000/sse" } } } ``` ##### 使用 Streamable HTTP 在網路上部署 MCP 伺服器: ```json { "mcpServers": { "http_google_search": { "type": "http", "url": "http://localhost:8000/mcp" } } } ``` #### 8-2 使用公開在網路上的 MCP 伺服器 ##### GitMCP 使用方法 ```json { "mcpServers": { "sse_google_search": { "url": "http://localhost:8000/sse" }, "gitmcp": { "type": "openai", "url": "https://gitmcp.io/idosal/git-mcp" } } } ``` ##### 使用 OpenAI 內建工具連接部署在公開網路上的 MCP 伺服器 - [Colab 筆記本](https://colab.research.google.com/drive/1qvaIlGVAZWEITFyW8WbgPYfQgA6dEJmW?usp=sharing) #### 8-3 使用環境變數傳遞機密資訊給 MCP 伺服器 :::warning 請記得修改 MCP 伺服器執行檔的路徑為你自己專案的路徑。 ::: ##### 預設揭露給 MCP 伺服器的環境變數 ```json { "mcpServers": { "show environ": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_environ.py" ] } } } ``` ##### 使用 env 項目傳遞環境變數給 MCP 伺服器 ```json { "mcpServers": { "show environ": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_environ.py" ], "env": { "FAKE_API_KEY": "my_fake_api_key" } } } } ``` #### 8-4 操控其他應用程式的 MCP 伺服器 ##### 測試控制 Spotify 的 MCP 伺服器 ```json { "mcpServers": { "spotify": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_spotify.py" ], "env": { "SPOTIFY_CLIENT_ID": "你的 Client id", "SPOTIFY_CLIENT_SECRET": "你的 Client secret" } } } } ``` ### 第 9 章 - [範例下載](https://github.com/FlagTech/F5762_realtime/archive/refs/heads/master.zip) #### 9-3 進入 Realtime API 的語音世界 ##### 用語音控制 MCP 伺服器 ```json { "mcpServers": { "spotify": { "command": "uv", "args": [ "--directory", "C:/temp/mcp_test", "run", "server_spotify.py" ], "env": { "SPOTIFY_CLIENT_ID": "你的 Client id", "SPOTIFY_CLIENT_SECRET": "你的 Client secret" } } } } ``` ### 第 10 章 - [Colab 筆記本](https://colab.research.google.com/drive/1n1VkVBxfO54GEbJ6EIEOagopU3aMuxyy?usp=sharing) - [範例檔案下載](https://github.com/FlagTech/F5762_agents_sdk/archive/refs/heads/master.zip) ## 勘誤 ### 第 2 章 #### 2-29 頁輸入圖片的計費方式 - gpt-4.1 的計費方式比照 gpt-4o - gpt-4.1 mini 與 gpt-4.1-nano 說明中『以短邊縮小到 32 的倍數』,實際上會以短邊及長邊都各試算一次,最後**以區塊數少**的為準,再轉換成 token 數 ### 第 5 章 #### 5-23 頁最下方 FunctionCallingCommand 類別的 make_tool_msg 函式 原本的程式碼如下: ```python=25 # 叫用單一函式並且將函式執行結果組成訊息後傳回 def make_tool_msg(self, tool_call): tool_info = f'{tool_call.name}(**{tool_call.arguments})' if self.verbose: print(f'叫用:{tool_info}') result = eval(tool_info) return { # 建立可傳回函式執行結果的字典 "type": "function_call_output", # 以工具角色送出回覆 "call_id": tool_call.call_id, # 叫用函式的識別碼 "output": result # 函式傳回值 } ``` 但因為 API 回覆的引數內容是 JSON 格式,會遇到像是 true/false 與 Python 的 True/False 大小寫不同的問題,最好先從 JSON 轉回 Python 後再執行函式,如下所示: ```python=25 # 叫用單一函式並且將函式執行結果組成訊息後傳回 def make_tool_msg(self, tool_call): tool_info = f'{tool_call.name}(**{tool_call.arguments})' if self.verbose: print(f'叫用:{tool_info}') func = eval(tool_call.name) args = json.loads(tool_call.arguments) result = func(**args) return { # 建立可傳回函式執行結果的字典 "type": "function_call_output", # 以工具角色送出回覆 "call_id": tool_call.call_id, # 叫用函式的識別碼 "output": result # 函式傳回值 } ``` ### 第 6 章 #### 6-3 頁最下方儲存格程式碼 這裡程式碼與上一段重複,應該是如下[整理執行結果為 markdown 格式](https://colab.research.google.com/drive/1pVisiBOP3iCqWxhXvw_OHUP9NUq-gLvx?authuser=1#scrollTo=TAcv3QqeZPok&line=1&uniqifier=1): ```python=1 output_md = ( f'執行結果\n\n```\n' f'{result.stdout.decode("utf8")}\n' f'```\n\n錯誤訊息\n\n```\n' f'{result.stderr.decode("utf8")}\n' f'```\n\n結束碼:{result.returncode}' ) print(output_md) ``` #### 6-32 頁 - 中間的程式碼: ```python=27 def handle_command(self, chat, cmd): if not super().handle_command(chat, cmd): return False idx = chat.find_tool_index(self.tool_name) if idx == -1: chat.tools.append({ 'type': self.tool_name, 'partial_images': 3 if self.verbose else 0 }) else: chat.tools.pop(idx) return True ``` 中間第 34 行原本在非 verbose 模式時設定變化圖為 0 張,不過因為會採用串流方式,必須設定至少為 1 張,因此這裡改為 1: ```python=27 def handle_command(self, chat, cmd): if not super().handle_command(chat, cmd): return False idx = chat.find_tool_index(self.tool_name) if idx == -1: chat.tools.append({ 'type': self.tool_name, 'partial_images': 3 if self.verbose else 1 }) else: chat.tools.pop(idx) return True ``` - 最下方程式碼: ```python=40 def handle_event(self, chat, stream, event): if event.type == 'response.completed': b64_data = self.get_img_b64(event.response.output) if not b64_data: return None elif event.type == ( 'response.image_generation_call.partial_image' ): b64_data = event.partial_image_b64 else: return None return get_img_obj(b64_data) ``` 最後一行漏掉了 `self.`,應該為: ```python=40 def handle_event(self, chat, stream, event): if event.type == 'response.completed': b64_data = self.get_img_b64(event.response.output) if not b64_data: return None elif event.type == ( 'response.image_generation_call.partial_image' ): b64_data = event.partial_image_b64 else: return None return self.get_img_obj(b64_data) ```