
提到 AI Agent很多教程会先介绍规划、记忆、工具调用和多智能体协作。这些概念都重要但初学者很容易遇到一个问题名词大概听懂了打开编辑器以后还是不知道第一行代码应该写什么。这个系列从一个具体项目开始技术支持与工单助手。我们会逐步实现知识库问答、工单查询、草稿生成、人工确认和任务恢复。本篇先搭好项目骨架跑通输入、调用和输出。不需要申请 API Key也不需要安装数据库。一、这个系列最终要做什么假设用户输入产品升级后出现 E104 错误帮我查一下怎么解决。 如果仍然需要人工处理帮我整理一份工单草稿。最终的系统应该能够理解问题 ↓ 查询产品文档 ↓ 根据证据解释处理方法 ↓ 必要时补充询问 ↓ 生成工单草稿 ↓ 用户确认 ↓ 创建工单并返回编号这里既有模型擅长的工作也有程序必须负责的工作。工作主要负责者理解用户描述模型选择合适的查询工具模型提出调用请求检查用户是否能访问工单应用程序执行数据库查询工具实现保存工单业务程序根据查询结果组织回答模型模型提出行动程序执行行动。后续所有设计都会围绕这个边界展开。二、聊天机器人、工作流和 Agent 有什么区别用这个项目举例更容易理解。1. 聊天机器人用户问题 → 模型 → 回答模型可以解释常见概念但没有接入工单系统就无法知道某张工单的真实状态。2. 固定工作流收到问题 → 一定搜索文档 → 一定生成答案步骤主要由代码预先确定。3. Agent收到问题 ↓ 模型根据任务和现有结果决定下一步 ├─ 直接回答 ├─ 查询文档 ├─ 查询工单 └─ 向用户补充询问一个实际应用可以混合使用固定流程与模型决策。例如是否搜索由模型判断但创建工单前的参数校验由程序固定执行。本系列先实现普通对话再逐步加入工具与执行循环。这样每一次结构变化都有具体原因。三、准备开发环境本系列前两篇使用Python 3.11 或以上版本 终端 任意代码编辑器只使用 Python 标准库暂时没有第三方依赖。先检查版本python --version创建目录mkdir support-agent cd support-agent创建虚拟环境python -m venv .venvWindows PowerShell 激活.\.venv\Scripts\Activate.ps1macOS 或 Linux 激活source .venv/bin/activate如果 PowerShell 不允许执行激活脚本也可以直接使用虚拟环境中的解释器.\.venv\Scripts\python.exe main.py虚拟环境激活的主要作用是让终端优先使用对应解释器不激活也可以通过完整路径运行。四、先用两个文件划分职责项目结构support-agent/ ├── main.py ├── client.py └── .gitignore职责分别是main.py用户输入、会话管理、结果展示 client.py接收消息返回回答暂时不需要复杂的分层架构。但把客户端独立出来有一个好处下一篇接入真实模型时可以保留命令行代码。五、实现模拟客户端创建client.pydef chat(messages: list[dict[str, str]]) - str: question messages[-1][content] return ( f[模拟模式] 已收到{question}\n 当前版本只验证输入、调用和输出流程 尚未接入模型或工单系统。 )这里约定输入一组消息 输出一段回答文本消息使用如下结构{ role: user, content: 请解释一下 E104 错误 }模拟客户端没有理解能力只是读取最后一条消息并返回固定格式的文本。它的用途是先检查程序流程不代表已经实现了 Agent。六、实现命令行对话创建main.pyfrom client import chat SYSTEM_PROMPT ( 你是技术支持助手请用中文清晰回答。 当前没有接入工单数据库和外部工具。 不要声称查询过工单或完成了业务操作 缺少信息时明确说明。 ) def main(): messages [ {role: system, content: SYSTEM_PROMPT} ] print( 技术支持助手 输入 /exit 退出/clear 清空会话。 ) while True: try: text input(你).strip() except (EOFError, KeyboardInterrupt): print(\n会话结束。) break if text /exit: break if text /clear: messages messages[:1] print(助手会话已清空。) continue if not text: continue pending messages [ {role: user, content: text} ] try: answer chat(pending) except RuntimeError as exc: print(f调用失败{exc}) continue messages pending [ {role: assistant, content: answer} ] print(f助手{answer}) if __name__ __main__: main()运行python main.py示例交互技术支持助手输入 /exit 退出/clear 清空会话。 你帮我查一下工单 T1001 助手[模拟模式] 已收到帮我查一下工单 T1001 当前版本只验证输入、调用和输出流程尚未接入模型或工单系统。 你/clear 助手会话已清空。 你/exit七、这段代码有哪些值得理解的设计1. 为什么用 messages 列表一次对话通常不只有当前问题。后续模型可能需要同时看到系统说明 用户第一轮问题 助手第一轮回答 用户第二轮问题列表保留了这些消息的顺序。但当前记录只存在内存中退出程序就会丢失。2. 为什么先创建 pending代码没有直接执行messages.append( {role: user, content: text} )而是先构造本次待发送消息pending messages [ {role: user, content: text} ]只有调用成功后才把这一轮完整记录加入会话。这样下一篇发生网络错误时不会把失败请求误当成已经完成的对话轮次。失败日志以后可以单独保存它与模型上下文不是同一份数据。3. 为什么 /clear 保留第一条消息第一条是系统说明messages messages[:1]清空聊天内容时保留助手的基本职责。模拟模式不使用系统说明但下一篇的真实模型请求会发送它。4. 为什么提前处理 RuntimeError模拟客户端目前不会产生网络错误。但我们约定客户端把可以展示给用户的调用失败包装成RuntimeError命令行负责显示。这样错误处理不必散落到所有层。八、补上 .gitignore创建.gitignore.venv/ __pycache__/ *.pyc .env .env.* !.env.example这里忽略了常见的本地配置文件但需要注意.gitignore不会自动保护已经提交过的文件。本系列目前没有读取.env的代码。后续密钥先通过终端环境变量传入。九、本篇验收按照下面的顺序检查操作预期结果输入一句话返回明确标注的模拟回复输入空白内容不产生调用连续输入两次程序继续运行输入/clear清空历史保留系统说明输入/exit正常退出按下 CtrlC 等待输入时正常结束会话当前版本不具备真实问答、工单查询、持久化和工具执行能力。这些会在后续逐步加入。课后练习增加一个/history命令打印当前消息的角色和内容。完成后思考聊天记录越来越长会不会让模型请求越来越大下一篇接入真实 API 后这个问题就会变得具体。下一篇第一次调用大模型 API——请求、响应、环境变量与错误处理。