你是一名软件工程师。你的技艺经过多年精心打磨。突然间,出现了这些聊天机器人和智能体。你的同事们一夜之间在 LinkedIn 上获得了新头衔:“AI 工程师”。有些人已经成为高级 AI 工程师。你对这个新世界充满好奇,可能想要迎头赶上并成为其中一员。
如果你就是这样的人,那么就和我一起踏上这场 AI 工程领域概念与模式的探索之旅。我们会发现 AI 应用开发在很大程度上“只是”软件工程,只是应用在了一个真正奇怪的新非确定性组件上:LLM。
在这次探索中,我们将构建一个真实的应用程序,从头到尾。每篇文章都会添加一个新层。我们会将新模式和新术语与你已经熟悉的软件工程概念联系起来。
在起飞前,我想先确立一个贯穿全文的词汇规则:“模型”指 LLM 本身(大语言模型,如 GPT 或 Claude),而 AI 工程师围绕它构建的东西将被称为“应用”、“智能体”或“框架”。
我们在构建什么
由于我本人就在一家支付公司工作,我决定坚持自己的领域。PayIQ,即我们构建的应用,是一个帮助商家执行支付操作的助手:发起退款、处理拒付、计算手续费。给它一个扣款金额和支付方式,它就能计算出实际退款成本(剧透:比退款金额多)。问它是否值得为拒付辩护,它会使用你的知识库进行预期价值计算。问它一些它无法负责任回答的问题,它会询问缺少的信息。不猜测,不幻觉。
到最后,PayIQ 将具备可被其他系统消费的结构化输出、一套金融计算器工具、知识库检索、带持久记忆的智能体循环、包含模型无法跳过步骤的编排图、FastAPI 服务后的 token 流式传输、回归评估套件以及分层注入防御。如果你对其中一些术语还不理解,不用担心。从现在开始,只是时间问题。
每篇文章阅读时间 10-15 分钟,并有意建立在前面的内容之上(第 2 部分的结构化输出将在第 3 部分的工具使用中用到),所以我建议按顺序阅读。第一篇文章奠定基础,并与模型进行简单交互。
配套代码仓库(https://github.com/BjornvdLaan/ai-engineering-articles-code-samples)包含所有代码示例,你可以自己尝试。示例使用 Anthropic 的模型。如果你更喜欢不同的提供商(或本地托管的模型),我相信你最喜欢的聊天机器人可以帮你调整配置。别担心,LangChain 的库(大多)与模型无关。
思考模型的心智模型
在进入代码之前,让我们先建立一个准确的模型心智模型。不是神经网络或 Transformer 内部如何工作——我们把这些留给聪明的科学家们。你作为一名有抱负的 AI 工程师需要的是操作性心智模型:这个东西消耗什么、成本如何,以及你可以控制什么。最简单的形式,模型只是这样一个接口:
f(list of input messages) -> output message
Enter fullscreen mode Exit fullscreen mode
就是这样。一个重要的细节是输入是消息的列表,而不仅仅是你给出的最后一个提示。每次调用模型通常包括一条系统消息(“应用配置”)、到目前为止的整个对话(“当前状态”)以及最新的提示。给定所有这些前置消息,模型生成对话中的下一条消息。
如果你使用过 Codex、Claude Code 或其他“框架”,这可能会听起来很奇怪。你会看到它搜索互联网、记住之前会话中的事实、维护待办事项列表、阅读你给它的文档、编写和编辑代码库。所有这些魔法都是 AI 工程师在模型周围构建的应用逻辑,但模型看到的只是输入消息的列表。
Token:一切的基本单位
消息以 token 而非字符或单词的形式发送给模型。一个名为 tokenizer 的组件首先将文本拆分为 token,并为每个 token 分配一个数字 ID。常见单词通常是一个 token,而不常见单词可能被拆分为多个。模型从不看到原始文本:它只处理这些 token ID。
除了作为计算单位,token 也很重要,因为它们是计费单位。你按输入和输出 token 付费。要像对待云账单中的计算秒一样对待 token。AI 功能是第一种单次请求成本大到需要关注的后端端点。一个每个用户请求进行五次模型调用的智能体在生产流量规模下会产生真实成本。这也是一种新的安全风险。传统上,DDoS 攻击主要消耗基础设施资源(CPU、内存、带宽和自动扩展实例)。现在,每个请求还可能消耗可计费的 token,增加了第二个可能大得多的成本组成部分。这种攻击甚至有自己的名字:拒绝钱包攻击。
上下文窗口:模型的输入限制
每个模型都有一个可以处理的最大输入 token 数。这被称为上下文窗口,通常可以容纳数十万个 token。如上所述,模型回答请求所需的一切都必须放入其中:你的系统提示、到目前为止的对话、检索到的文档、工具结果以及你提供的任何其他上下文。把它看作模型的工作记忆。更大的上下文窗口让你可以提供更多信息,但更多上下文并不总是更好。随着无关信息的积累,模型会有更多干扰,重要细节更容易被遗漏。你会看到这被称为上下文腐烂。更多输入 token 也会让你花费更多!这就是为什么“把所有东西都粘贴进去”无法扩展:上下文工程是关于质量而非数量。
设置
现在我们已经了解了一些背景信息,是时候看看模型是如何工作的了。这个设置对整个系列的所有代码示例只需要一次。
前提条件:Python 3.11+、你最喜欢的提供商的 API 密钥,以及整个系列不到五欧元的额度。
创建一个新项目目录(或克隆配套仓库)并激活 Python 虚拟环境:
python3 -m venv .venv
source .venv/bin/activate
Enter fullscreen mode Exit fullscreen mode
创建 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
Enter fullscreen mode Exit fullscreen mode
其中大多数包是用于后续部分(检索、MCP、Web 层),但现在安装它们意味着你以后再也不需要修改这个文件。
运行 pip install -r requirements.txt,然后在项目根目录创建 .env。这是你存储 API 密钥(以及可选的其他配置)的地方:
ANTHROPIC_API_KEY=sk-ant-...
Enter fullscreen mode Exit fullscreen mode
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)
Enter fullscreen mode Exit fullscreen mode
运行它:python3 01_first_call.py。
代码示例中有两个细节需要注意。首先,init_chat_model 是 LangChain 的提供商无关构造函数。字符串 "anthropic:claude-sonnet-5" 也可以是 "openai:gpt-5.5" 或 "ollama:llama3.3",而你的其余应用代码保持不变。这也是软件工程师针对抽象而非具体实现编程的相同原因:当你需要因成本、能力和合规原因切换提供商时,你只需更改配置而无需重新设计系统。
其次,看一下响应中的 usage_metadata。它显示了该调用的输入和输出 token。这些数字决定了成本。生产级 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}}
Enter fullscreen mode Exit fullscreen mode
为什么每次输出可能不同
如你所见,第二次运行 01_first_call.py 会得到不同的答案。问它一些它实际上不知道的问题,它可能会非常自信地编造一个答案。这两种行为都源于同一个地方:模型生成文本的方式。
模型一次生成一个输出 token。在每一步,模型为每个可能的下一个 token 预测概率,采样一个,附加到输入,然后重复以获得下一个输出 token。从这个单一机制产生了两个后果,这两个后果对我们之后构建的一切都很重要。
第一个是非确定性。模型并不是每次都选择最可能的 token。相反,它从分布中采样,因此相同的输入在下一次调用时可能产生不同的输出。采样的自由度以及你是否可以影响它,因模型而异。有些模型提供 temperature 设置。与这种非确定性打交道是与“普通”软件工程的关键区别。
第二个是幻觉,即你可能听说过的模型编造故事。这可以追溯到模型的构建方式。它的设计目的是预测下一个 token,而不是区分什么是真实的。模型不是在检索事实;它在生成似是而非的文本。如果一个问题有正确答案但模型缺乏必要信息,它可能会自信地生成一个令人信服但不正确的内容。模型创建者应用“后训练”来教导模型遵循指令、使用特定格式、拒绝某些请求,并更频繁地承认不确定性。但它仍然没有给模型一个内部事实检查器。
注意,这是同一枚硬币的两面:一个采样似是而非的 token 而不是检索正确事实的模型。修复通常不是一个更好的提示。而是围绕模型构建一个系统,约束其输出,并在正确性重要时提供正确的信息。这个系统正是本系列其余部分构建的内容,也是 AI 工程师所做的事情。
你做到了!
干得好!你刚刚迈出了 AI 工程的第一步。我们学习了一些理论并进行了第一次模型调用。显然,这还不是特别有用。如果你的后端调用这个模型,那么你永远不知道会得到什么样的输出。输出消息是非结构化的,因此无法像处理 JSON 响应那样轻松解析为对象。下一篇文章将做 exactly that:确保模型的输出遵循你的代码可以依赖的结构。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.