發(fā)入門必懂的 10 個(gè) Agent 核心概念:用 TaoToken 統(tǒng)一 Key 跑通第一個(gè) Agent 示例)
1. 從“會(huì)聊天”到“會(huì)干活”Agent 開(kāi)發(fā)入門到底在學(xué)什么很多人第一次接觸 Agent 開(kāi)發(fā)腦子里其實(shí)只有一個(gè)模糊印象不就是讓大模型自己調(diào)工具、自己干活嗎但真動(dòng)手寫的時(shí)候問(wèn)題立刻冒出來(lái)——它為什么知道該調(diào)哪個(gè)工具它怎么記住上一輪說(shuō)過(guò)的話任務(wù)拆到一半卡住了怎么辦這些疑問(wèn)背后其實(shí)對(duì)應(yīng)的是 Agent 的十個(gè)核心概念。把這十個(gè)概念串起來(lái)你才算真正跨過(guò)了 Agent 開(kāi)發(fā)入門的門檻。這篇內(nèi)容聚焦一件事把抽象概念落到可運(yùn)行的最小 Agent 示例上。我會(huì)用統(tǒng)一的 Key 和 API 通道在本地跑通一個(gè)能規(guī)劃、能調(diào)工具、能記住上下文的 Agent然后逐項(xiàng)檢查每個(gè)概念是否真的生效。你不需要先啃完論文跟著配置和代碼走一遍概念自然就對(duì)應(yīng)上了。適合誰(shuí)看如果你已經(jīng)會(huì)調(diào)用大模型 API但沒(méi)寫過(guò) Agent 循環(huán)或者用過(guò) Claude Code 這類工具卻說(shuō)不清它內(nèi)部怎么“思考”再或者想自己搭一個(gè)能查天氣、能讀寫文件的小助手這篇就是為你準(zhǔn)備的。核心檢索詞就三個(gè)Agent、開(kāi)發(fā)、核心概念——我們邊跑邊理解。先明確一個(gè)前提Agent 不是某個(gè)具體框架而是一種運(yùn)行模式。它的最小骨架就是“感知 → 思考 → 行動(dòng) → 觀察”的循環(huán)。你后面看到的所有高級(jí)能力規(guī)劃、記憶、多 Agent 協(xié)作都是在這個(gè)循環(huán)上疊加出來(lái)的。所以第一步我們先把循環(huán)跑起來(lái)再談其他。2. 用 TaoToken 統(tǒng)一 Key 打通 Agent 的模型調(diào)用通道寫 Agent 最煩的一件事是模型調(diào)用通道不統(tǒng)一。今天試這個(gè)模型明天換那個(gè)接口Key 散落在各個(gè)環(huán)境變量里調(diào)試的時(shí)候光找配置就耗掉一半精力。我的做法是用一個(gè)統(tǒng)一的 API 通道把模型調(diào)用固定下來(lái)Agent 代碼里只認(rèn)一個(gè) Base URL 和一個(gè) Key換模型只改一個(gè) Model ID。這里我用 TaoToken 來(lái)做這件事。它的 API 地址是 https://taotoken.net/api兼容常見(jiàn)的 OpenAI 風(fēng)格調(diào)用方式所以你在 Agent 代碼里用 openai 這個(gè) SDK 就能直接連。對(duì) Agent 開(kāi)發(fā)入門來(lái)說(shuō)這一點(diǎn)很關(guān)鍵——你不需要為每個(gè)模型寫一套適配層統(tǒng)一通道能讓你的循環(huán)邏輯保持干凈。先拿 Key。打開(kāi) https://taotoken.net/api-keys 登錄后創(chuàng)建一個(gè) API Key復(fù)制出來(lái)。注意這個(gè) Key 只顯示一次先存到安全的地方。然后我們把它寫進(jìn)環(huán)境變量不要硬編碼在代碼里。在項(xiàng)目根目錄建一個(gè).env文件TAOTOKEN_API_KEYsk-你的key TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你用 Python裝兩個(gè)包pip install openai python-dotenv然后在代碼里這樣初始化客戶端import os from dotenv import load_dotenv from openai import OpenAI load_dotenv() client OpenAI( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlos.getenv(TAOTOKEN_BASE_URL), ) MODEL_ID claude-sonnet-4-5-20250929 # 按需替換這里有個(gè)細(xì)節(jié)Base URL 結(jié)尾不要帶/v1SDK 會(huì)自己拼路徑。如果你寫成https://taotoken.net/api/v1請(qǐng)求會(huì)變成/api/v1/v1/chat/completions直接 404。這個(gè)坑我踩過(guò)排查了半天。統(tǒng)一通道的好處在你寫 Agent 循環(huán)時(shí)會(huì)特別明顯。因?yàn)?Agent 一次任務(wù)可能要調(diào)用模型十幾次每次的請(qǐng)求格式都一樣只是消息歷史在變。如果通道不統(tǒng)一你會(huì)在不同模型的參數(shù)差異上浪費(fèi)大量時(shí)間?,F(xiàn)在你只需要關(guān)心消息怎么組織、工具怎么描述、循環(huán)怎么退出。另外提醒一句Key 不要提交到 Git。把.env加進(jìn).gitignore團(tuán)隊(duì)協(xié)作時(shí)用環(huán)境變量注入。Agent 項(xiàng)目里經(jīng)常會(huì)有多個(gè)工具和子進(jìn)程Key 泄露的風(fēng)險(xiǎn)比普通腳本高這點(diǎn)要養(yǎng)成習(xí)慣。3. 可復(fù)制的 Agent 最小配置Base URL、Key 與 Model ID 三件套概念要落地得先有一個(gè)能跑的最小 Agent。我們不追求功能多只追求把核心循環(huán)、工具調(diào)用、記憶這三件事跑通。下面這份配置你可以直接復(fù)制改掉 Key 就能用。先看目錄結(jié)構(gòu)mini-agent/ ├── .env ├── agent.py └── tools.py.env就是上一步那兩行。tools.py里定義兩個(gè)最簡(jiǎn)單的工具一個(gè)查時(shí)間一個(gè)算加法。工具描述要寫清楚因?yàn)槟P涂棵枋鰶Q定調(diào)哪個(gè)。# tools.py import datetime def get_current_time(city: str) - str: 獲取指定城市的當(dāng)前時(shí)間。當(dāng)用戶詢問(wèn)時(shí)間相關(guān)問(wèn)題時(shí)使用。 now datetime.datetime.now().strftime(%Y-%m-%d %H:%M:%S) return f{city} 當(dāng)前時(shí)間{now} def add_numbers(a: float, b: float) - str: 計(jì)算兩個(gè)數(shù)字的和。當(dāng)用戶需要做加法運(yùn)算時(shí)使用。 return f{a} {a b} TOOL_MAP { get_current_time: get_current_time, add_numbers: add_numbers, } TOOLS_SCHEMA [ { type: function, function: { name: get_current_time, description: 獲取指定城市的當(dāng)前時(shí)間。當(dāng)用戶詢問(wèn)時(shí)間相關(guān)問(wèn)題時(shí)使用。, parameters: { type: object, properties: { city: {type: string, description: 城市名稱} }, required: [city], }, }, }, { type: function, function: { name: add_numbers, description: 計(jì)算兩個(gè)數(shù)字的和。當(dāng)用戶需要做加法運(yùn)算時(shí)使用。, parameters: { type: object, properties: { a: {type: number, description: 第一個(gè)數(shù)字}, b: {type: number, description: 第二個(gè)數(shù)字}, }, required: [a, b], }, }, }, ]注意工具描述里的“當(dāng)用戶……時(shí)使用”。這不是寫給人看的注釋是寫給模型看的觸發(fā)條件。描述越具體模型選錯(cuò)工具的概率越低。我試過(guò)把描述寫成“處理數(shù)據(jù)”結(jié)果模型在需要算加法時(shí)去調(diào)了時(shí)間工具因?yàn)樗X(jué)得“處理”也能涵蓋。然后是主循環(huán)agent.py# agent.py import json import os from dotenv import load_dotenv from openai import OpenAI from tools import TOOL_MAP, TOOLS_SCHEMA load_dotenv() client OpenAI( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlos.getenv(TAOTOKEN_BASE_URL), ) MODEL_ID claude-sonnet-4-5-20250929 def run_agent(user_input: str, max_turns: int 5): messages [ {role: system, content: 你是一個(gè)會(huì)使用工具的助手。需要時(shí)調(diào)用工具不要憑空猜測(cè)。}, {role: user, content: user_input}, ] for turn in range(max_turns): response client.chat.completions.create( modelMODEL_ID, messagesmessages, toolsTOOLS_SCHEMA, tool_choiceauto, ) msg response.choices[0].message messages.append(msg) if not msg.tool_calls: print(f[最終回答] {msg.content}) return msg.content for tool_call in msg.tool_calls: name tool_call.function.name args json.loads(tool_call.function.arguments) print(f[調(diào)用工具] {name} 參數(shù){args}) result TOOL_MAP[name](**args) print(f[工具結(jié)果] {result}) messages.append({ role: tool, tool_call_id: tool_call.id, content: str(result), }) print([警告] 達(dá)到最大輪次強(qiáng)制結(jié)束) return None if __name__ __main__: run_agent(現(xiàn)在上海幾點(diǎn)順便幫我算一下 128 加 256 等于多少)這份配置里Base URL、Key、Model ID 三件套齊全。你把它保存下來(lái)python agent.py就能跑。跑通之后我們?cè)僦痦?xiàng)驗(yàn)證概念。4. 跑通第一個(gè) Agent 并逐項(xiàng)驗(yàn)證十個(gè)核心概念是否生效現(xiàn)在運(yùn)行python agent.py你會(huì)看到類似這樣的輸出[調(diào)用工具] get_current_time 參數(shù){city: 上海} [工具結(jié)果] 上海 當(dāng)前時(shí)間2026-01-15 14:32:07 [調(diào)用工具] add_numbers 參數(shù){a: 128, b: 256} [工具結(jié)果] 128 256 384 [最終回答] 上?,F(xiàn)在是 2026-01-15 14:32:07128 加 256 等于 384。一次任務(wù)里模型先調(diào)時(shí)間工具再調(diào)加法工具最后匯總回答。這個(gè)過(guò)程里十個(gè)核心概念其實(shí)都在悄悄起作用。我們逐項(xiàng)對(duì)照。核心循環(huán)Perceive 是用戶輸入Think 是模型決定調(diào)哪個(gè)工具Act 是執(zhí)行工具Observe 是工具結(jié)果回填到 messages。循環(huán)在for turn in range(max_turns)里轉(zhuǎn)了兩圈才結(jié)束。你可以把max_turns改成 1會(huì)看到它只調(diào)一個(gè)工具就被強(qiáng)制結(jié)束——這就是循環(huán)邊界的作用。工具調(diào)用模型輸出的tool_calls就是 Function Calling。它自己不執(zhí)行只是表達(dá)“我要調(diào) get_current_time參數(shù)是上?!?。真正執(zhí)行的是TOOL_MAP[name](**args)。MCP 在這個(gè)最小例子里沒(méi)出現(xiàn)但你可以理解為如果工具變多就需要一個(gè)協(xié)議來(lái)管理工具從哪來(lái)、怎么連那就是 MCP 要解決的問(wèn)題。規(guī)劃與任務(wù)分解用戶一句話里有兩個(gè)需求模型自動(dòng)拆成兩步先時(shí)間后加法。它沒(méi)有一次性把兩個(gè)工具都調(diào)了而是按順序來(lái)。這就是最樸素的規(guī)劃。你可以試著問(wèn)“先算 11再告訴我北京幾點(diǎn)最后把兩個(gè)結(jié)果拼起來(lái)”觀察它怎么排順序。記憶系統(tǒng)messages列表就是短期記憶。工具結(jié)果被 append 進(jìn)去模型下一輪能看到。如果你把messages清空再問(wèn)同樣的問(wèn)題它就不知道之前算過(guò)什么。長(zhǎng)期記憶需要你額外寫文件比如把用戶偏好存到MEMORY.md下次啟動(dòng)時(shí)讀進(jìn)來(lái)。上下文窗口管理這個(gè)例子里消息很短看不出壓力。但如果你把max_turns調(diào)到 20再讓它反復(fù)讀大文件就會(huì)遇到上下文超限。策略是按需加載——只把相關(guān)工具結(jié)果放進(jìn) messages不要把所有歷史都塞進(jìn)去。ReAct 范式模型在調(diào)工具前其實(shí)內(nèi)部有 Thought只是這個(gè)例子里沒(méi)顯式打印。你可以在 system prompt 里加一句“每次調(diào)用工具前先用一句話說(shuō)明你的理由”然后打印msg.content就能看到它的推理過(guò)程。多 Agent 協(xié)作最小例子里只有一個(gè) Agent。要驗(yàn)證多 Agent你可以起兩個(gè)進(jìn)程一個(gè)負(fù)責(zé)查時(shí)間一個(gè)負(fù)責(zé)算數(shù)用主進(jìn)程調(diào)度。但入門階段先不用急單 Agent 跑順了再擴(kuò)展。錯(cuò)誤處理把a(bǔ)dd_numbers的參數(shù)故意傳成字符串看模型怎么反應(yīng)。它可能會(huì)重試也可能直接報(bào)錯(cuò)。你可以在工具函數(shù)里加 try/except返回錯(cuò)誤信息給模型讓它自己糾正。安全與對(duì)齊這個(gè)例子里工具都是只讀的沒(méi)有風(fēng)險(xiǎn)。如果你加一個(gè)“刪除文件”工具就應(yīng)該在描述里寫“調(diào)用前必須確認(rèn)”并在代碼里加確認(rèn)邏輯。四層防御里人類確認(rèn)是最后一道。編排框架選型現(xiàn)在你是用原生 SDK 手寫循環(huán)。等任務(wù)復(fù)雜了可以考慮 LangGraph 這類框架。但入門階段手寫一遍能讓你真正理解每個(gè)環(huán)節(jié)后面用框架時(shí)才知道它在幫你做什么。跑完這一遍十個(gè)概念就不再是名詞而是你代碼里能指認(rèn)出來(lái)的具體位置。5. 常見(jiàn)報(bào)錯(cuò)排查401、local proxy failed 與 reading choices 怎么解Agent 開(kāi)發(fā)入門階段報(bào)錯(cuò)比概念更勸退。下面這幾個(gè)是我和身邊人最常遇到的對(duì)照著排查能省不少時(shí)間。401 Unauthorized最常見(jiàn)的原因是 Key 沒(méi)讀到。先確認(rèn).env文件在項(xiàng)目根目錄且load_dotenv()在OpenAI()之前調(diào)用。然后打印一下os.getenv(TAOTOKEN_API_KEY)看是不是 None。如果 Key 讀到了還報(bào) 401檢查 Key 有沒(méi)有多余空格或者是不是已經(jīng)失效。還有一種情況Base URL 寫成了https://taotoken.net/api/帶尾斜杠某些 SDK 會(huì)拼出雙斜杠導(dǎo)致鑒權(quán)失敗去掉尾斜杠即可。local proxy failed / connection error這個(gè)報(bào)錯(cuò)通常出現(xiàn)在網(wǎng)絡(luò)層。先確認(rèn)你的 Base URL 是https://taotoken.net/api不要寫成其他地址。然后在終端里用 curl 直接測(cè)一下curl https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-5-20250929,messages:[{role:user,content:hi}]}如果 curl 通而 Python 不通那是 SDK 或環(huán)境變量的問(wèn)題如果 curl 也不通檢查本機(jī)網(wǎng)絡(luò)設(shè)置。注意不要在任何配置里寫代理地址Agent 項(xiàng)目里混入代理配置會(huì)讓排查變得非?;靵y。reading choices 報(bào)錯(cuò) / choices 為空這個(gè)報(bào)錯(cuò)說(shuō)明請(qǐng)求發(fā)出去了但返回結(jié)構(gòu)里沒(méi)有choices。常見(jiàn)原因有三個(gè)。一是 Model ID 寫錯(cuò)了比如把claude-sonnet-4-5-20250929拼成了別的服務(wù)端返回錯(cuò)誤信息而不是正常補(bǔ)全。二是請(qǐng)求體里messages格式不對(duì)比如 role 寫成了assistant但 content 是空。三是觸發(fā)了內(nèi)容過(guò)濾返回了一個(gè)沒(méi)有 choices 的結(jié)構(gòu)。排查方法把response整個(gè)打印出來(lái)看response.error里有沒(méi)有信息。OAuth 相關(guān)報(bào)錯(cuò)如果你在 Claude Code 或類似工具里看到 OAuth 報(bào)錯(cuò)通常是因?yàn)楣ぞ邍L試用賬號(hào)登錄而不是 API Key。在 Agent 代碼里我們用的是 API Key 模式不會(huì)走 OAuth。如果你在配置 Claude Code 時(shí)遇到檢查它的 settings 里是不是把認(rèn)證方式設(shè)成了 API KeyBase URL 填https://taotoken.net/apiKey 填你創(chuàng)建的 KeyModel ID 填對(duì)應(yīng)模型。工具調(diào)用參數(shù)解析失敗如果json.loads(tool_call.function.arguments)報(bào)錯(cuò)說(shuō)明模型返回的參數(shù)不是合法 JSON。這通常是因?yàn)楣ぞ呙枋隼锏?parameters schema 寫得不嚴(yán)謹(jǐn)。檢查required字段和properties是否對(duì)應(yīng)類型是否寫對(duì)。另外有些模型在參數(shù)里會(huì)帶注釋導(dǎo)致 JSON 解析失敗可以在解析前做一次清洗。循環(huán)不退出如果 Agent 一直調(diào)工具不返回最終回答先看max_turns是不是設(shè)太大了。然后檢查工具結(jié)果是不是讓模型誤以為任務(wù)沒(méi)完成。比如時(shí)間工具返回了結(jié)果但模型覺(jué)得還需要再確認(rèn)一次??梢栽?system prompt 里加一句“拿到工具結(jié)果后如果信息足夠直接給出最終回答”。6. 把概念變成手感下一步用統(tǒng)一 Key 繼續(xù)練跑通最小示例之后你對(duì) Agent 開(kāi)發(fā)入門的十個(gè)核心概念已經(jīng)有了手感。接下來(lái)最有效的練習(xí)是每次只改一個(gè)變量觀察行為變化。比如把工具描述改模糊看模型選錯(cuò)工具把max_turns改成 1看循環(huán)怎么被截?cái)喟?messages 清空看記憶怎么丟失。這種對(duì)照實(shí)驗(yàn)比讀十篇文章都管用。如果你想把模型調(diào)用通道固定下來(lái)繼續(xù)用 TaoToken 的 API 就行Base URL 還是https://taotoken.net/apiKey 在 https://taotoken.net/api-keys 創(chuàng)建。想直接對(duì)話驗(yàn)證模型行為可以打開(kāi) https://taotoken.net/model-chat 試幾句。如果你打算長(zhǎng)期寫 Agent、跑編碼類任務(wù)可以看看 Coding Planhttps://taotoken.net/coding-plan 它更適合高頻調(diào)用場(chǎng)景。接入文檔在 https://taotoken.net/doc 配置細(xì)節(jié)都在里面。最后留一個(gè)練習(xí)給最小 Agent 加一個(gè)“寫文件”工具但要求它在調(diào)用前先輸出一句確認(rèn)語(yǔ)。觀察模型會(huì)不會(huì)遵守這個(gè)約束如果不遵守你打算在哪一層攔截。這個(gè)練習(xí)會(huì)把你對(duì)安全與對(duì)齊的理解從概念推到代碼。