你是一位軟體工程師。多年來,你已透過謹慎的實踐磨練出你的技藝。然後突然之間,出現了這些聊天機器人與代理程式。隔夜,你的同事在 LinkedIn 上獲得了一個新頭銜:「AI 工程師」。有些人已經是「資深 AI 工程師」了。你對這個新世界感到好奇,可能也想迎頭趕上並成為其中一員。

如果這就是你,那麼就加入我一起遊覽 AI 工程領域中的概念與模式吧。我們將發現,AI 應用程式開發大多只是「單純」的軟體工程,應用於一個真正奇異的、非確定性元件:LLM。

在這趟旅程中,我們將端對端地建構一個真實的應用程式。每篇文章都會新增一層。我們會將新的模式與詞彙連結到你已知的既有軟體工程概念。

在起飛之前,我想先確立一個貫穿全文的詞彙規則:「模型」指的是 LLM 本身(大型語言模型,例如 GPT 或 Claude),而 AI 工程師在它周圍建構的東西將被稱為「應用程式」、「代理程式」或「外殼」。

我們在建構什麼

由於我本身在一家支付公司工作,我決定就待在我的領域。PayIQ,我們正在建構的應用程式,是一個協助商家執行支付作業的助理:發出退款、應對退單、計算處理費。給它一個收費金額和一種支付方式,它就能計算實際的退款成本(劇透:比退款金額還多)。詢問它是否值得為一筆退單抗爭,它會使用你的知識庫進行預期值計算。詢問它無法負責任地回答的問題,它會詢問缺少什麼。不猜測、不幻覺。

到最後,PayIQ 將具備可供其他系統使用的結構化輸出、一整套金融計算器、知識庫檢索、帶有持久性記憶的代理程式迴圈、帶有模型無法跳過之步驟的編排圖、FastAPI 服務背後的權杖串流、迴歸評估套件,以及分層注入防禦。如果其中一些詞彙對你來說毫無意義,也不用擔心。從現在開始,只是時間早晚的問題。

每篇文章的閱讀時間為 10-15 分鐘,並刻意建立在前面的內容之上(第 2 部分的結構化輸出將用於第 3 部分的工具使用),因此我建議依序閱讀。本文第一篇奠定基礎,並與模型進行簡單的互動。

配套的程式碼儲存庫(https://github.com/BjornvdLaan/ai-engineering-articles-code-samples)包含所有程式碼範例,讓你也能親自嘗試。這些範例使用 Anthropic 的模型。如果你偏好不同的供應商(或本地託管的模型),我相信你最愛的聊天機器人可以幫助你調整設定。不用擔心,LangChain 的函式庫(大多數)是模型無關的。

思考模型的心智模型

在進入程式碼之前,讓我們先建立一個關於模型實際是什麼的準確心智模型。我們不會探討神經網路或 transformer 內部如何運作——我們會把那留給聰明的科學家。你作為有志成為 AI 工程師的人,需要的是操作性的心智模型:這個東西消耗什麼、成本多少,以及你可以控制什麼。最簡單的形式是,模型就是這個介面:

f(list of input messages) -> output message

進入全螢幕模式 離開全螢幕模式

就是這樣。一個重要的細節是,輸入是一個訊息清單,而非你給出的最後一個提示。通常,每次呼叫模型都會包含一則系統訊息(「應用程式設定」)、到目前為止的完整對話(「目前狀態」),以及最新的提示。根據所有這些先前的訊息,模型會產生對話中的下一則訊息。

如果你曾使用過 Codex、Claude Code 或其他「外殼」,這聽起來可能有點奇怪。你會看到它搜尋網際網路、從先前的對話中記憶事實、維護待辦事項清單、閱讀你給它的文件、撰寫和編輯程式碼庫。所有這些魔法都是 AI 工程師在模型周圍建構的應用程式邏輯,但模型所看到的只是輸入訊息的清單。

權杖:一切的單位

訊息是以權杖的形式傳送給模型,而不是字元或單字。一個稱為 tokenizer 的元件首先將文字分割成權杖,並為每個權杖分配一個數值權杖 ID。常見的單字通常是一個權杖,而不常見的單字可能會被分割成多個。模型永遠看不到原始文字:它只處理這些權杖 ID。

除了作為運算單位之外,權杖也很重要,因為它是計費單位。你需要為輸入和輸出權杖付費。對待權杖的方式就像對待雲端帳單中的運算秒數。AI 功能是第一種單一請求成本高到需要關注的後端端點。一個每用戶請求發出五次模型呼叫的代理程式,在生產環境的流量規模下會產生真正的金錢成本。這也是一種新的安全風險。傳統上,DDoS 攻擊主要消耗基礎設施資源(CPU、記憶體、頻寬和自動擴展的執行個體)。現在,每個請求也可能消耗可計費的權杖,增加第二個可能大得多的成本組成部分。這種攻擊甚至有自己的名稱:拒絕錢包(denial of wallet)。

上下文視窗:模型的輸入限制

每個模型都有一個可處理的最大輸入權杖數。這被稱為其上下文視窗,通常可以容納數十萬個權杖。如上所述,模型回答請求所需的所有內容都必須裝在裡面:你的系統提示、到目前為止的對話、檢索到的文件、工具結果,以及你提供的任何其他上下文。把它想像成模型的工作記憶體。較大的上下文視窗可讓你提供更多資訊,但更多上下文不一定更好。隨著無關資訊累積,模型會有更多干擾,重要細節也更容易被忽略。你會看到這被稱為上下文腐壞(context rot)。更多的輸入權杖也會讓你花更多錢!這就是為什麼「直接全部貼上」無法擴展:上下文工程的重點在於品質而非數量。

設定

現在我們已經有了一些背景資訊,是時候看看模型實際運作的樣子了。本系列的所有程式碼範例都需要進行一次此設定。

先決條件:Python 3.11+、你最愛的供應商的 API 金鑰,以及整系列不到五歐元的點數。

建立一個新的專案目錄(或複製配套儲存庫)並啟動 Python 虛擬環境:

python3 -m venv .venv
source .venv/bin/activate

進入全螢幕模式 離開全螢幕模式

建立 requirements.txt

langchain>=1.3,<2.0
langchain-core>=1.4,<2.0
langchain-text-splitters>=1.1,<2.0
langgraph>=1.2,<2.0
langgraph-swarm>=0.1
langchain-anthropic>=0.4
langchain-huggingface>=0.2
sentence-transformers>=3.0
langchain-mcp-adapters>=0.1
mcp>=1.9
fastapi>=0.115
uvicorn>=0.32
pydantic>=2.9
python-dotenv>=1.0

進入全螢幕模式 離開全螢幕模式

這些套件大多數是用於後續部分(檢索、MCP、網路層),但現在就安裝它們,意味著你再也不需要碰這個檔案。

執行 pip install -r requirements.txt,然後在專案根目錄建立 .env。這是你存放 API 金鑰(以及其他設定)的地方:

ANTHROPIC_API_KEY=sk-ant-...

進入全螢幕模式 離開全螢幕模式

Anthropic 的 API 金鑰可從 platform.claude.com 取得。

你的第一次呼叫

建立 01_first_call.py

from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

load_dotenv()

model = init_chat_model("anthropic:claude-sonnet-5")

response = model.invoke(
    "A customer is disputing a €480 online card payment, claiming they "
    "never made it. In two sentences, what are the two most important "
    "pieces of evidence I should gather before responding?"
)

print(response.content)
print("\n--- metadata ---")
print(response.usage_metadata)

進入全螢幕模式 離開全螢幕模式

執行它:python3 01_first_call.py

程式碼範例中有兩個細節需要注意。首先,init_chat_model 是 LangChain 的供應商無關建構函式。字串 "anthropic:claude-sonnet-5" 也可以是 "openai:gpt-5.5""ollama:llama3.3",而其餘的應用程式程式碼保持不變。這也是軟體工程師針對抽象層而不是具體實作進行程式設計的同樣原因:當你需要因成本、功能或合規性原因切換供應商時,你可以變更設定而不是重新設計系統。

其次,看看回應中的 usage_metadata。它顯示了該次呼叫的輸入和輸出權杖。這些數字決定了成本。生產環境的 AI 系統監控它們的方式,與傳統應用程式監控資料庫查詢、記憶體使用量和其他資源消耗的方式相同。你需要在 Grafana 儀表板上看到這些數字。

以下是輸出可能呈現的範例。我們會執行兩次。

$ python3 01_first_call.py

The two most critical pieces of evidence are:

1. **Transaction authentication records** - Check whether the payment was verified through 3D Secure/Strong Customer Authentication (SCA), as successful two-factor authentication significantly shifts liability away from you and toward the cardholder or their bank.

2. **Delivery/fulfillment proof** - Gather evidence that the goods or services were delivered to the address or account linked to the cardholder, such as signed delivery confirmation, IP address logs, or account activity showing the customer used what was purchased.

--- metadata ---
{'input_tokens': 45, 'output_tokens': 119, 'total_tokens': 164, 'input_token_details': {'cache_read': 0, 'cache_creation': 0, 'ephemeral_5m_input_tokens': 0, 'ephemeral_1h_input_tokens': 0}}

$ python3 01_first_call.py

Pull the transaction's authentication data (AVS/CVV match results, and whether 3-D Secure/EMV 3DS was used with a successful cardholder authentication, e.g., SCA challenge completion) and the device/IP/geolocation and behavioral data captured at checkout (billing/shipping address match, device fingerprint, past purchase history from that account) to establish whether the legitimate cardholder likely completed the transaction. Also gather delivery confirmation or service usage records (proof of delivery, IP login after purchase, downloads, or usage logs tied to the account) to show the goods or services were actually received or accessed by the customer.

--- metadata ---
{'input_tokens': 57, 'output_tokens': 209, 'total_tokens': 266, 'input_token_details': {'cache_read': 0, 'cache_creation': 0, 'ephemeral_5m_input_tokens': 0, 'ephemeral_1h_input_tokens': 0}}

進入全螢幕模式 離開全螢幕模式

為什麼每次輸出可能不同

如你所見,第二次執行 01_first_call.py 會給出不同的答案。詢問它實際上無法知道的事情,它可能會充滿信心地編造一個答案。這兩種行為都來自同一個地方:模型產生文字的方式。

模型一次產生一個輸出權杖。在每個步驟中,模型會為每個可能的下一個權杖預測一個機率,取樣一個,附加到輸入,然後重複以取得下一個輸出權杖。從這個單一機制產生兩個後果,這兩個後果對我們之後建立的所有東西都很重要。

第一個是非確定性。模型並非每次都只挑選最有可能的權杖。相反,它從分佈中取樣,因此相同的輸入在下一次呼叫時可能產生不同的輸出。取樣的自由度有多大,以及你是否能影響它,取決於每個模型。有些模型提供 temperature 設定。處理這種非確定性是與「一般」軟體工程的一個關鍵差異。

第二個是幻覺(hallucination),你可能聽過模型編造事情的故事。這可以追溯到模型的建構方式。它被設計成預測下一個權杖,而不是區分什麼是實際上正確的。模型不是在檢索事實;它是在產生看似合理的文字。如果一個問題有正確答案,但模型缺乏必要資訊,它可能會自信地產生一個令人信服但不正確的答案。模型建立者會套用「後訓練」來教導模型遵循指令、使用特定格式、拒絕某些請求,並更常承認不確定性。但這仍然無法給模型一個內部事實驗證器。

請注意,這是同一枚硬幣的兩面:一個取樣看似合理的權杖而非檢索正確事實的模型。修正方法通常不是更好的提示。而是在模型周圍建立一個系統,來約束其輸出,並在正確性很重要時給它正確的資訊。這個系統正是本系列其餘部分所建構的東西,也是 AI 工程師的工作。

你做到了!

做得好!你剛踏出了進入 AI 工程的第一步。我們學習了一些理論並發出了第一次模型呼叫。顯然,這還不是非常有用。如果你的後端呼叫這個模型,那麼你永遠不知道會得到什麼樣的輸出。輸出訊息是沒有結構的,因此無法像我們處理 JSON 回應那樣輕鬆地解析成物件。下一篇文章將確實做到這一點:確保模型的輸出遵循你的程式碼可以依賴的結構。