在第 2 章中,我们探讨了 AI 智能体的基础概念:它们的架构、组件,以及它们如何与工具和外部系统交互。我们也讨论了这些原则(例如智能体循环与记忆)在流行的 AutoGen(github.com/microsoft/a…)框架中是如何实现的。在本章中,我们将在此基础上,通过剖析一个简单的 AI 智能体 k8s-ai 来加深理解。k8s-ai 能够以“一行一行”的方式与 Kubernetes 集群交互。随着我们走读代码并准确理解智能体循环如何工作,带有工具访问能力的 AI 智能体的威力会变得非常直观。而把这个简单智能体与一个访问 Kubernetes 的工具结合起来,也将展示:即便是如此基础的配置,也可以非常能打。
我们将先铺垫场景:介绍 k8s-ai 智能体,并通过运行它、在聊天界面中与它交互来展示其能力。当你亲身体验过 k8s-ai 的智能体能力之后,我们会解释这个智能体系统在底层是如何工作的。
在本章中,我们将涵盖以下主要内容:
- 介绍 k8s-ai
- 理解 k8s-ai 智能体系统
- 技术要求
技术要求
请确保你的机器上安装了 kubectl、Docker 和 kind。如果尚未安装,请参考以下安装说明:
- Kubectl 安装说明(kubernetes.io/docs/tasks/…
- Docker 安装说明(docs.docker.com/engine/inst…
- kind 安装说明(kind.sigs.k8s.io/docs/user/q…
简单说明一下我们为什么需要它们:
- kubectl 是用于与 Kubernetes 集群交互与管理的命令行工具,通过向 Kubernetes API server 发送命令来工作。
- Docker 是容器平台,把应用及其依赖打包成轻量、可移植的容器,并能在不同环境中一致运行。
- Kubernetes in Docker(KinD) 是一个使用 Docker 容器作为集群节点来运行本地 Kubernetes 集群的工具,主要用于开发与测试。
你阅读本章时应使用这些工具的最新版本。
如果你想跟着本章代码示例一起操作,请确保已安装 Python(www.python.org/downloads/)。
你还需要一个 OpenAI API key,可在 OpenAI 平台获取:platform.openai.com/api-keys 。
你可以参考 README.md 中的说明(github.com/PacktPublis…)或(github.com/the-gigi/k8…)来把 k8s-ai 智能体跑起来。
介绍 k8s-ai 智能体
k8s-ai 智能体(github.com/the-gigi/k8…)是一个用单个 Python 文件实现的简单 AI 智能体,它可以通过 kubectl(kubernetes.io/docs/refere…)工具与Kubernetes(kubernetes.io/)集群交互。如果你不熟悉 Kubernetes,也没关系。一句话概括:它是一个用于自动化部署、扩缩容与管理容器化应用的开源系统。kubectl 则是与 Kubernetes 集群交互的命令行接口。
在深入之前,我们先“试驾”一下,看看它能做什么。
用 kind 搭建本地集群
我们先用 kind(kind.sigs.k8s.io/)搭一个本地 Kubernetes 集群。kind 是一个在 Docker 容器里运行 Kubernetes 集群的工具,非常适合本地开发与测试。
我们可以用 kind 创建一个本地集群。运行以下命令创建名为 k8s-ai 的集群:
kind create cluster -n k8s-ai
创建过程会输出类似如下信息(略):
Creating cluster "k8s-ai" ...
✓ Ensuring node image (kindest/node:v1.33.1)
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-k8s-ai"
You can now use your cluster with:
kubectl cluster-info --context kind-k8s-ai
Have a nice day! 👋
我们验证一下集群是否正常运行:
kubectl cluster-info --context kind-k8s-ai
Kubernetes control plane 正在运行于 https://127.0.0.1:52864 。
CoreDNS 正在运行于 https://127.0.0.1:52864/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy 。
如需进一步调试与诊断集群问题,可使用 kubectl cluster-info dump 。
很好!本地 Kubernetes 集群已经跑起来了。现在,我们来给集群“添点乱子”。下面这个 Deployment 永远不会就绪,因为它要求 Pod 必须调度到带有一个集群中不存在的 label 的节点上:
echo '
apiVersion: apps/v1
kind: Deployment
metadata:
name: some-app
spec:
replicas: 3
selector:
matchLabels:
app: some-app
template:
metadata:
labels:
app: some-app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: no-such-node
operator: In
values:
- "true"
containers:
- name: pause
image: registry.k8s.io/pause:3.9
' | kubectl apply -f -
输出:
deployment.apps/some-app created
我们确认一下所有 Pod 都创建了,但因为 label 要求,它们都处于 Pending:
kubectl get po
NAME READY STATUS RESTARTS AGE
some-app-65696dbff4-8jdrj 0/1 Pending 0 6s
some-app-65696dbff4-mbfv7 0/1 Pending 0 6s
some-app-65696dbff4-wj9ms 0/1 Pending 0 6s
我们甚至可以通过查看其中一个 Pod 的状态,看到 Pending 的确切原因(1 node(s) didn't match Pod's node affinity/selector.):
kubectl get po some-app-65696dbff4-8jdrj -o yaml | grep status: -A 10
输出(节选):
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2025-06-05T08:45:45Z"
message: '0/1 nodes are available: 1 node(s) didn''t match Pod''s node affinity/selector.
preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.'
reason: Unschedulable
status: "False"
type: PodScheduled
phase: Pending
qosClass: BestEffort
再来点“更大的破坏”:我们创建一个 NGINX(一个常见 Web 服务器)的 Deployment,但用一个错误的镜像名(nnnnnnnnginx):
echo '
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nnnnnnnnginx
' | kubectl apply -f -
输出:
deployment.apps/nginx created
现在看一下集群状态:
kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-74f5dd8d8f-p2hmh 0/1 ImagePullBackOff 0 91s
some-app-65696dbff4-8jdrj 0/1 Pending 0 9m3s
some-app-65696dbff4-mbfv7 0/1 Pending 0 9m3s
some-app-65696dbff4-wj9ms 0/1 Pending 0 9m3s
我们现在有两个 Deployment:some-app 和 nginx。some-app 有三个 Pending 的 Pod;nginx 有一个 Pod 因镜像名错误进入错误状态。接下来我们看看如何用 k8s-ai 智能体来帮我们处理这种局面。
运行 k8s-ai 智能体
首先,你需要 clone k8s-ai 仓库:
git clone git@github.com:the-gigi/k8s-ai.git
按 README.md(github.com/PacktPublis…)的说明运行并与 k8s-ai 交互。
激活虚拟环境后,直接运行:
python main.py
你会看到如下输出,然后就可以开始与智能体交互:
Interactive Kubernetes Chat. Type 'exit' to quit.
👤 You:
k8s-ai 已启动并准备好交互。我们通过自然语言对话来检查集群。
用 k8s-ai 检查集群
所有基础模型都大量学习过 Kubernetes 知识,包括 kubectl CLI,因此它们应该能与我们的 Kubernetes 集群进行有意义的交互。
好,我们来问智能体关于集群的情况:
👤 You: what's going on in the cluster?
🤖 AI: Here's a summary of the current state of the cluster:
(以下略,保持原输出结构)
这非常酷!智能体给出了集群状态的详细摘要,包括 Pod、Service、Deployment 等,并且识别出了 nginx 与 some-app 两个 Deployment 的问题。
我们再深入一点,看看它能否定位 Pending Pod 的根因:
👤 You: find out why the some-app pods are pending
🤖 AI: The "some-app" pods are in a "Pending" state because they cannot be scheduled...
(以下略)
没错。智能体正确识别了:some-app 的 Pod 因节点亲和性/选择器要求无法满足而无法调度,并建议检查亲和性或选择器要求。那我们让它直接给出具体可执行方案?注意有时你可能得到比较泛的回答,这时你可以用更强的提示词让它更具体:
👤 You: suggest concrete solutions to fix this. don't ask me to check anything. you check.
🤖 AI: The root cause ... requires scheduling on nodes with the label no-such-node=true...
(以下略)
智能体准确定位了根因并给出了具体方案。第 3 条“Review other constraints”仍然不够具体(它其实可以自己跑检查),但我们先放过,因为前两条方案足够好。到目前为止,它只对集群做了读操作。
我们让它执行方案 #2:给节点打上所需 label:
👤 You: Go ahead with solution #2 and label the node with no-such-node=true
🤖 AI: The node k8s-ai-control-plane has been successfully labeled...
很好!智能体说已成功给节点打 label。我们再检查一下 Pod 状态:
kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-74f5dd8d8f-p2hmh 0/1 ImagePullBackOff 0 6h46m
some-app-65696dbff4-8jdrj 1/1 Running 0 15m34s
some-app-65696dbff4-mbfv7 1/1 Running 0 15m34s
some-app-65696dbff4-wj9ms 1/1 Running 0 15m34s
成功了!我们的 AI 智能体能诊断集群问题、给出解决方案、在有 human-in-the-loop 授权的情况下修复问题。
好,我们再“疯狂”一点:让它自己把 nginx Deployment 彻底修好:
👤 You: nice, it works! now go ahead an fix the nginx problem on your own. just tell me in the end what you did.
🤖 AI: I resolved the issue with the nginx deployment by updating its image...
非常棒!智能体做出了判断:既然 deployment 名叫 nginx,那么正确镜像也应该是 nginx。我们照例验证一下 nginx Pod 的状态确认修复:
kubectl get po -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-5869d7778c-kbpjz 1/1 Running 0 2m30s
是的!新 Pod 已创建并处于 Running。智能体在没有任何人类干预的情况下自行修复了问题。
现在,我们已经准备好更深入代码,理解 k8s-ai 智能体在底层是如何工作的。接下来我们将探索 k8s-ai 的代码结构。
理解 k8s-ai 智能体系统
在我们进入代码之前,先理解一下智能体 AI 系统的原则是如何与 k8s-ai 对齐的。
图 3.1:k8s-ai 智能体工作流
在 k8s-ai 的示意图中,你可以看到以下流程:
- 用户与 k8s-ai 的
main()函数交互,main()充当控制性的 AI 系统。 main()调用由send()函数实现的智能体循环(agentic loop)。send()使用的工具定义中只包含一个工具:kubectl。send()把用户的 prompt 发送给 LLM,LLM 可能返回工具请求以调用kubectl。send()会针对 Kubernetes 集群执行这些kubectl命令,并把结果返回给 LLM,直到 LLM 返回最终回复;send()将该最终回复返回给main(),main()将其展示给用户,然后准备接收用户的新查询。
理解了 k8s-ai 智能体的工作流之后,我们再来看它是如何实现的。
k8s-ai 智能体的代码走读
我们先从宏观层面看一下 k8s-ai 仓库里的 main.py 文件,不展开太多细节。
Imports
k8s-ai 智能体先引入内置包(如 json、os),再引入第三方库 sh 与 openai:
import json
import os
import sh
from openai import OpenAI
json 用于解析 OpenAI API 的响应;os 用于读取环境变量(例如 OPENAI_API_KEY);sh 模块用于运行 shell 命令(这里就是 kubectl)。
OpenAI 客户端
k8s-ai 使用官方 OpenAI Python client 与 OpenAI API 交互。它用环境变量里的 API key 初始化 client。严格来说这一步并非必需,因为默认情况下 OpenAI client 会去找这个同名环境变量;但我更倾向于在代码中显式设置,便于理解,也避免依赖隐蔽的默认行为。这里使用的模型是 gpt-4o,它足够强大,能胜任当前任务。
client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])
model_name = "gpt-4o"
注意 client 并没有在初始化时绑定 model 参数,因为模型是在每次 API 请求中指定的。这样如果你之后想换模型,不需要改 client。k8s-ai 在所有请求里都使用同一个模型,但这并不是硬性要求。
更复杂的智能体系统往往会为不同任务选用不同提供商的不同模型;但 k8s-ai 虽然已经很强(我们已经见识过),它的设计目标是简单与教学。
工具
我们已经反复提到:AI 智能体的能力上限取决于它能访问的工具。k8s-ai 定义了一份工具列表,这里只包含一个工具——对 kubectl 命令行的封装。我们会在下一节更细致地分析它。
tools = [{
...
}]
智能体循环
智能体循环是 k8s-ai 的核心。它操作一份 messages 列表(由字典组成),并把最终回复作为字符串返回。我们很快会逐行拆解这个循环;现在先看 send() 的函数签名——它完整封装了整个智能体循环:
def send(messages: list[dict[str, any]]) -> str:
...
main() 函数
最后,main() 是 k8s-ai 的入口:它用 system message 初始化 messages 列表,负责与用户交互,并把核心工作都委派给 send()。我们稍后会在“实现工具调用执行循环”一节看到它的具体做法。
def main():
...
if __name__ == "__main__":
main()
接下来,我们看看如何为智能体使用 OpenAI tools。
用 OpenAI 定义并注册工具
k8s-ai 智能体的目标是与 OpenAI client 交互,并用 kubectl 工具管理 Kubernetes 集群。它需要遵循 OpenAI API 的工具定义格式。需要注意的是,工具有不同类型。k8s-ai 使用的是 function calling,也就是 "function" 类型的工具。函数工具包含名称、描述、参数、必填参数列表;你也可以指定是否启用 strict 模式。更多细节请参考 OpenAI 文档(platform.openai.com/docs/guides…)。
下面是 k8s-ai 的 tools 列表的完整定义(只包含 kubectl 工具):
tools = [{
"type": "function",
"function": {
"name": "kubectl",
"description": "execute a kubectl command against the current k8s cluster",
"parameters": {
"type": "object",
"properties": {
"cmd": {
"type": "string",
"description": (
"the kubectl command to execute (without kubectl, just "
"the arguments). For example, 'get pods'"
),
},
},
"required": ["cmd"],
},
},
}]
我们逐块拆解:
tools 列表
tools 是一个 list,可定义一个或多个工具。list 中每个元素是一个 dict,代表一个工具。这里我们只定义一个工具:kubectl 函数。
tools = [
{
...
}
]
type
这告诉 OpenAI API:该工具是 function tool。函数工具使用 function calling,模型可以自动选择并用它构造出来的参数来调用工具。工具定义的其余部分放在 "function" 子字典下:
"type": "function"
"function": { ... }
name
这是模型调用工具时使用的名称,应简短、描述性强,并在所有已注册工具中保持唯一。这里选择 kubectl 很合适,因为它是 LLM 在训练中很可能见过的常用工具名。
"name": "kubectl"
description
description 为函数提供额外上下文,解释它的目的与用法,应清晰简洁。这里描述很基础,因为 LLM 应该已经知道 kubectl 的用途。
函数描述必须包含足够信息,使模型(LLM)能够在任何给定情境下判断是否应调用该工具:
"description": "execute a kubectl command against the current k8s cluster"
始终是 LLM 基于它收到的信息(prompt 与工具描述)来做决定。
在 k8s-ai 中,AI 系统就是一个简单的 chat 界面:打印 LLM 的最终回复,然后等待用户输入。
回忆我们在第 2 章讨论的 AutoGen:它有很多抽象层,也需要把这些抽象里的信息转换成 prompt 与工具描述再发给 LLM。一般而言,构建在 AI 框架之上的 AI 系统,在接收到每次智能体循环的最终回复后,还可能决定运行额外的自定义代码,而不只是展示最终回复。
parameters
parameters 描述函数期望的输入,以 JSON Schema 格式定义,其中 type 总是 "object",而 "properties" 字段列出函数可接收的具体参数。每个参数有名称(这里是 "cmd")、类型(这里是 "string")以及描述。
因为 kubectl 有很多子命令及其参数,这里我们只定义一个字符串参数来代表要执行的完整命令。我们在这里依赖 LLM 的训练,让它理解如何构造 kubectl 命令。cmd 参数也被标记为必填。kubectl 虽然可以不带参数运行(只会打印 help),但在这里没什么用,所以要求模型调用工具时必须提供 cmd。
"parameters": {
"type": "object",
"properties": {
"cmd": {
"type": "string",
"description": (
"the kubectl command to execute (without kubectl, just "
"the arguments). For example, 'get pods'"
),
},
},
"required": ["cmd"],
}
注意:函数工具并不定义输出。这意味着模型并不知道函数调用结果的形状与结构;它会收到一个字符串输出,然后自行解析并决定如何使用。这是 LLM + 工具的常见模式:模型可以处理多种输出形式,不需要提前知道结构。要求开发者强制定义输出结构会带来很大摩擦,尤其像 kubectl 这种输出可能千变万化、格式多样的工具。
实现工具调用执行循环
现在我们更近一步看智能体循环:它如何与 OpenAI API 交互以调用 kubectl 工具。这是 k8s-ai 的核心:向 OpenAI API 发送消息、接收响应、执行 kubectl 命令。令人意外的是,这个智能体循环非常简单,只有 18 行代码。完整代码如下:
def send(messages: list[dict[str, any]]) -> str:
response = client.chat.completions.create(
model=model_name, messages=messages,
tools=tools, tool_choice="auto")
r = response.choices[0].message
if r.tool_calls:
message = dict(
role=r.role,
content=r.content,
tool_calls=[dict(id=t.id, type=t.type,
function=dict(name=t.function.name,
arguments=t.function.arguments)
) for t in r.tool_calls if t.function])
messages.append(message)
for t in r.tool_calls:
if t.function.name == 'kubectl':
cmd = json.loads(t.function.arguments)['cmd'].split()
result = sh.kubectl(cmd)
messages.append(dict(tool_call_id=t.id, role="tool",
name=t.function.name, content=result))
return send(messages)
return r.content.strip()
逐步拆解如下:
1)函数签名
这一行定义了核心循环函数 send():输入是消息 dict 列表(与 OpenAI 的 messages 参数一致),输出是最终 assistant 消息的文本内容(string)。
def send(messages: list[dict[str, any]]) -> str:
2)调用 Chat Completions API
这一行调用 OpenAI API,根据 messages 生成回复。它使用 Chat Completions API 的 chat.completions.create()(platform.openai.com/docs/api-re…)。
它传入固定的模型名(gpt-4o)、消息列表、工具列表(只有 kubectl),并把 tool_choice 设为 "auto",允许模型基于当前对话状态自行决定是否调用工具。
response = client.chat.completions.create(
model=model_name, messages=messages,
tools=tools, tool_choice="auto"
)
OpenAI 最近还发布了另一个更强大、更灵活的 API:Responses API;但 k8s-ai 不需要那么多“花活”。
3)取第一条输出消息
OpenAI API 可以一次返回多个 choice,但实践中通常只有一个。因此 k8s-ai 直接取第一个 choice,并抽出 message 对象:
r = response.choices[0].message
4)检查是否包含工具调用
如果响应里有 tool calls,就说明模型决定使用工具执行某个动作:
if r.tool_calls:
5)构造 tool calls 消息
这时需要准备一个 message dict,包含 role、content 与 tool_calls。tool_calls 会被转换成一个 dict 列表,包含工具调用 ID(来自 LLM)、type、函数名与参数。这样才能在对话历史里跟踪每次工具调用以及对应结果。
message = dict(
role=r.role,
content=r.content,
tool_calls=[dict(
id=t.id,
type=t.type,
function=dict(
name=t.function.name,
arguments=t.function.arguments
)) for t in r.tool_calls if t.function]
)
注意:一次响应里可能有多个工具调用。即便你只注册了一个工具,模型也可能多次调用它并使用不同参数。例如它可能要在不同 namespace 下执行多条 kubectl 命令(如 get pods)。
6)把 tool calls 消息追加到 messages
这一步很直接:把刚构造的 message dict append 到 messages 列表里,以保持对话线程最新:
messages.append(message)
7)对每个工具调用执行 kubectl
接着遍历响应中的每个 tool call。如果是 kubectl,就解析参数里的 cmd 并按空格拆分为命令行参数列表。例如 "get pods" 变成 ["get", "pods"]。然后用 sh 执行 kubectl:
for t in r.tool_calls:
if t.function.name == 'kubectl':
cmd = json.loads(t.function.arguments)['cmd'].split()
result = sh.kubectl(cmd)
8)把工具结果追加回 messages
工具执行后,把结果 append 成一条新的消息:包含原始 tool call 的 ID(让 LLM 知道哪个结果对应哪个调用)、role 设为 "tool"、函数名(这里总是 kubectl)以及执行输出内容。这就是智能体把工具结果“喂回”模型的方式,供下一轮循环使用:
messages.append(dict(
tool_call_id=t.id,
role="tool",
name=t.function.name,
content=result
))
9)递归继续循环
只要模型回复里还有 tool calls,智能体就持续处理。send() 用更新后的 messages(包含模型的工具请求与工具结果)递归调用自己,继续循环:
return send(messages)
在可生产系统里,你通常会设定最大迭代次数或最长时间,超出则视为失败并返回错误给用户。实际中,LLM 也往往自带收敛机制:如果它无法收敛到满意解,会自行返回错误。
10)返回最终回复
当响应里不再包含工具调用时,send() 返回模型最终回复的内容:
return r.content.strip()
注意这里并不返回完整 response 对象或 messages 全量历史,只返回最后一条消息的 content。某些 AI 框架会提供钩子让你访问完整消息历史;但 k8s-ai 的目标是保持简单。
运行并与 Kubernetes 聊天智能体交互
最后,k8s-ai 提供了一个交互式命令行界面(CLI)来与智能体交互。
main() 函数先打印欢迎信息,并用 system message 初始化 messages 列表,为智能体设定上下文:
def main():
print(" Interactive Kubernetes Chat. Type 'exit' to quit.\n" + "-" * 52)
messages = [{'role': 'system', 'content': 'You are a Kubernetes expert ready to help'}]
然后进入交互循环:等待用户输入,把输入 append 到 messages,调用 send(messages) 运行智能体循环直到获得最终回复,打印到屏幕,循环往复,直到用户输入 'exit':
while (user_input := input("👤 You: ")).lower() != 'exit':
messages.append(dict(role="user", content=user_input))
response = send(messages)
print(f" AI: {response}\n----------")
每条用户消息都会启动一个新的智能体循环,但 messages 历史在各次循环间被保留,这使智能体能够在对话中维持上下文与连续性。历史被保存在内存中,所以用户输入 exit 后一切都会消失。
更复杂的智能体会使用更复杂的记忆管理系统来存储与检索消息。
你现在已经从两个视角体验了一个完整 AI 智能体:作为用户,用它解决真实问题;作为开发者,逐行理解其内部机制。对“消息如何在智能体循环中流动、工具如何定义与调用、以及简单代码如何创造强大的自治行为”的这种动手理解,构成了你构建自己智能体的基础。下面我们在总结中把这些洞察收拢起来。
总结
在本章中,我们走出纯理论,看到一个 AI 智能体在现实中运行:它用自治、推理与工具的组合控制一个真实的 Kubernetes 集群。k8s-ai 智能体用 61 行 Python(包含空行与 imports)构建,却极其能干。尽管很简单,它展示了多项 AI 智能体的基础能力。
系统能够通过 kubectl 检查集群状态,从而有效观察当前条件;它借助 OpenAI API 诊断问题并定位根因;它理解何时以及如何使用 kubectl——不仅用于收集信息,也用于做必要变更;它以 human-in-the-loop 方式运行,除非明确指示其自治执行,否则会在做修改前请求许可;在运行过程中,它保持对话上下文、按需调用工具,并把工具输出反馈给语言模型,从而形成一个连贯的智能体循环。
我们创建了坏掉的 Deployment,把 scheduler 搞懵,甚至在 KinD 集群里故意破坏了容器镜像。k8s-ai 都搞定了。我们也看到:OpenAI 的 function-calling 接口配合一个定义清晰的工具与少量胶水代码,就能把一个由 LLM 驱动的智能体系统“点亮”,并且还带交互式聊天界面。
更广泛地说,本章证明了 AI 智能体不一定非得臃肿、脆弱或过度工程化。只要你清楚它们如何运作——消息、工具、记忆与智能体循环——你就能构建有用且可靠的系统,用来增强人类工作流,甚至在受控环境中自治运行。
在下一章中,我们将基于与 k8s-ai 相同的原则,开始构建一个完整的智能体 AI 框架之旅。