从零开始实现一个 AI Agent CLI
1. 引言
AI Agent 正在成为大模型应用的主流形态。相比一次性的问答,Agent 能够自主规划、调用工具、循环执行,直到完成一个复杂目标。而 CLI(命令行界面)是体验 Agent 能力最直接、最轻量的方式:没有前端、没有服务端,一个终端窗口就能跑起来。
本文将从零开始,手把手实现一个可运行的 AI Agent CLI。我们会先明确 Agent 的核心组成,再逐步搭建项目、实现工具调用循环、接入大模型,最后封装成命令行工具。全程使用 Python,代码可直接复制运行。
2. Agent 的核心概念
在动手写代码之前,先厘清几个关键概念。
2.1 什么是 Agent
Agent 是一个能感知环境、做出决策并采取行动的智能体。在 LLM 语境下,Agent 通常指:大模型作为「大脑」,通过循环调用工具(Tool)来完成任务。
2.2 ReAct 模式
ReAct(Reasoning + Acting)是 Agent 最经典的实现范式,核心循环如下:
- 模型根据当前状态进行推理(Thought)
- 模型决定调用哪个工具、传入什么参数(Action)
- 程序执行工具并返回结果(Observation)
- 模型根据观察继续推理,直到给出最终答案(Final Answer)
2.3 工具(Tool)
工具是 Agent 与外部世界交互的接口。一个工具通常包含:名称、描述、参数定义(JSON Schema)、执行函数。模型通过描述来决定何时调用、如何传参。
3. 项目初始化
我们先创建项目结构和虚拟环境。
mkdir ai-agent-cli
cd ai-agent-cli
python -m venv .venv
source .venv/bin/activate # Windows 使用 .venv\Scripts\activate
安装依赖:
pip install openai python-dotenv
创建项目文件:
ai-agent-cli/
├── agent/
│ ├── __init__.py
│ ├── core.py # Agent 主循环
│ ├── tools.py # 工具定义
│ └── llm.py # 大模型调用封装
├── main.py # CLI 入口
└── .env # API Key 配置
4. 定义工具层
我们先实现工具层。这里以「获取当前时间」和「计算器」两个工具为例,演示如何定义可被模型调用的工具。
# agent/tools.py
import datetime
import json
from typing import Any, Callable, Dict
def get_current_time() -> str:
"""获取当前日期和时间"""
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def calculator(expression: str) -> str:
"""计算数学表达式,如 '1 + 2 * 3'"""
# 安全起见,只允许数字和运算符
allowed = set("0123456789+-*/(). ")
if not all(c in allowed for c in expression):
return "错误:表达式包含非法字符"
try:
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except Exception as e:
return f"计算错误:{e}"
# 工具注册表:名称 -> (函数, 描述, 参数Schema)
TOOLS: Dict[str, Dict[str, Any]] = {
"get_current_time": {
"function": get_current_time,
"description": "获取当前日期和时间",
"parameters": {
"type": "object",
"properties": {},
},
},
"calculator": {
"function": calculator,
"description": "计算数学表达式",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如 '1 + 2 * 3'",
}
},
"required": ["expression"],
},
},
}
def execute_tool(name: str, arguments: Dict[str, Any]) -> str:
"""根据名称和参数执行工具"""
if name not in TOOLS:
return f"错误:未知工具 {name}"
func: Callable = TOOLS[name]["function"]
try:
result = func(**arguments)
return str(result)
except Exception as e:
return f"工具执行失败:{e}"
5. 封装大模型调用
接下来封装 OpenAI 兼容接口的调用。这里使用 openai 库,通过环境变量读取 API Key 和 Base URL,方便对接不同厂商。
# agent/llm.py
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"),
)
MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
def chat(messages: list, tools: list | None = None):
"""调用大模型,支持工具调用"""
kwargs = {"model": MODEL, "messages": messages}
if tools:
kwargs["tools"] = tools
response = client.chat.completions.create(**kwargs)
return response.choices[0].message
在 .env 文件中配置:
OPENAI_API_KEY=sk-xxxx
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4o-mini
6. 实现 Agent 主循环
这是整个 CLI 的核心。我们实现 ReAct 循环:把工具定义传给模型,模型返回工具调用请求时,我们执行工具并把结果追加到消息历史,然后再次调用模型,直到模型给出最终文本回复。
# agent/core.py
import json
from .llm import chat
from .tools import TOOLS, execute_tool
SYSTEM_PROMPT = """你是一个智能助手,可以通过调用工具来完成任务。
请根据用户的问题,自主决定是否调用工具以及调用哪个工具。
当工具返回结果后,结合结果继续推理,直到给出最终答案。"""
def build_tool_schemas() -> list:
"""把工具注册表转换为 OpenAI 工具格式"""
schemas = []
for name, meta in TOOLS.items():
schemas.append(
{
"type": "function",
"function": {
"name": name,
"description": meta["description"],
"parameters": meta["parameters"],
},
}
)
return schemas
def run_agent(user_input: str, max_steps: int = 5) -> str:
"""运行 Agent 主循环,返回最终回答"""
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_input},
]
tool_schemas = build_tool_schemas()
for step in range(max_steps):
print(f"\n[Step {step + 1}] 调用模型...")
message = chat(messages, tools=tool_schemas)
# 模型没有工具调用请求,说明已给出最终答案
if not message.tool_calls:
return message.content or "(模型未返回内容)"
# 把模型的工具调用请求加入历史
messages.append(
{
"role": "assistant",
"content": message.content,
"tool_calls": [
{
"id": tc.id,
"type": "function",
"function": {
"name": tc.function.name,
"arguments": tc.function.arguments,
},
}
for tc in message.tool_calls
],
}
)
# 逐个执行工具,并把结果加入历史
for tc in message.tool_calls:
name = tc.function.name
args = json.loads(tc.function.arguments or "{}")
print(f" 调用工具: {name}({args})")
result = execute_tool(name, args)
print(f" 工具返回: {result}")
messages.append(
{
"role": "tool",
"tool_call_id": tc.id,
"content": result,
}
)
return "已达到最大步数,任务未完成。"
7. 编写 CLI 入口
最后,把 Agent 封装成命令行工具。支持两种模式:单次提问和交互式对话。
# main.py
import sys
from agent.core import run_agent
def interactive():
"""交互式对话模式"""
print("AI Agent CLI 已启动,输入 exit 退出。")
while True:
user_input = input("\n你: ").strip()
if user_input.lower() in ("exit", "quit"):
break
if not user_input:
continue
answer = run_agent(user_input)
print(f"\nAgent: {answer}")
def main():
if len(sys.argv) > 1:
# 单次提问模式:python main.py "你的问题"
question = " ".join(sys.argv[1:])
print(run_agent(question))
else:
interactive()
if __name__ == "__main__":
main()
8. 运行与测试
现在可以运行了。先试单次提问:
python main.py "现在几点了?"
预期输出类似:
[Step 1] 调用模型...
调用工具: get_current_time({})
工具返回: 2026-09-15 17:25:24
[Step 2] 调用模型...
Agent: 现在是 2026 年 9 月 15 日 17:25:24。
再试计算器:
python main.py "计算 (12 + 34) * 5 的结果"
再试交互模式:
python main.py
9. 扩展思路
到这里,一个最小可用的 AI Agent CLI 已经完成。你可以在此基础上继续扩展:
- 增加更多工具:在
TOOLS注册表中添加即可,如文件读写、网络请求、数据库查询。 - 支持多轮记忆:把历史对话持久化到本地文件,实现跨会话记忆。
- 流式输出:使用
stream=True让模型回复逐字打印,体验更流畅。 - 错误重试:当工具调用参数解析失败时,把错误信息回传给模型让其自我修正。
- 子 Agent:让一个 Agent 调用另一个 Agent,实现任务分解与协作。
10. 总结
本文从零实现了一个 AI Agent CLI,核心要点如下:
- Agent 的本质是「模型 + 工具 + 循环」。
- ReAct 模式通过 Thought → Action → Observation 的循环完成任务。
- 工具层用统一的注册表管理,模型通过 JSON Schema 感知工具。
- 主循环的关键是维护消息历史,把工具调用和结果正确回传给模型。
整个实现不到 200 行代码,却具备了 Agent 最核心的能力。你可以在此基础上不断叠加功能,打造属于自己的 AI 助手。
更多推荐


所有评论(0)