简介:本文从工程化视角出发,讲解如何从零搭建一个可独立运行、可被后端调用的Python Agent服务。读者将掌握配置分层、DTO设计、模型客户端封装、RAG与工具链编排、输入护栏与测试策略等关键环节,并理解如何通过轻量验证节奏控制迭代风险,最终得到一个具备健康检查、对话与计划生成能力的完整服务骨架。
很多团队第一次接入大模型时,写的都是一段“能跑就行”的脚本:读一个环境变量,拼一段 prompt,调用一次接口,打印结果。这样的代码在演示阶段没问题,但一旦要交给后端服务调用、要接入真实用户流量、要做回归测试,它立刻暴露出三个问题:配置散落、边界缺失、无法验证。本章的目标不是让模型“说一句话”,而是把模型调用放进一套完整的工程结构里,交付一个可以独立运行、后续能被业务后端调用的 Python Agent 服务。
在动手写代码之前,先把服务的契约固定下来。一个最小但完整的 Agent 服务,应当暴露四类端点:
GET /health:返回服务存活状态与当前生效的模型配置摘要(模型标识、超时、是否启用真实调用等),用于部署探活与排障。POST /agent/chat:接收用户消息,依次经过输入护栏、检索增强(RAG)、工具调用和主模型链路,返回结构化响应。POST /agent/today:基于用户档案与打卡记录,生成当日的计划内容。POST /rag/ingest:接收文本,完成切块并写入最小化的向量存储,为 /agent/chat 提供检索上下文。这四个端点覆盖了“健康可观测、对话可编排、业务可落地、知识可更新”四个维度。把它们定清楚,后面的目录结构和测试点就有了依据。
推荐的最小目录划分如下(示意,非强制):
app/main.py # 应用入口与路由注册config.py # 配置加载与校验schemas.py # DTO 定义llm_client.py # 模型客户端封装guardrails.py # 输入护栏rag_store.py # 最小 RAG 存储与切块tools.py # 工具注册与调度orchestrator.py # 服务编排:护栏→RAG→工具→模型tests/test_health.pytest_chat.pytest_ingest.py
这个结构的关键在于职责隔离:config.py 只负责把环境变量收敛成强类型对象;llm_client.py 只负责一次模型调用的超时、重试与异常归一化;orchestrator.py 负责决定“先做什么、后做什么、失败时降级到哪”。这样当模型供应商变化、或者编排策略调整时,改动面被限制在单层内。
配置层要解决两件事:一是默认安全,二是显式开启。
# 理解片段,不要复制:展示配置对象应包含的字段语义class Settings:model_name: strbase_url: strapi_key: str | Nonetimeout_s: floatenable_real_llm: bool # 默认 False
这里最关键的设计是 enable_real_llm 默认为 False。默认测试路径不依赖任何真实密钥,走的是可预测的假客户端;只有显式打开开关,才会发起真实模型调用。这条规则的价值在于:CI 环境永远稳定,本地开发也不会因为忘记配密钥而大面积失败。
DTO 层同理。请求体用显式字段而不是裸字典,响应体固定 code / message / data 三段式。结构化的代价是几行代码,收益是接口契约可被测试断言、可被前端稳定消费。
客户端封装要处理四类问题:超时、重试、异常归一化、可替换性。
# 理解片段,不要复制:客户端接口的抽象形态class LLMClient:def chat(self, messages: list[dict], **kwargs) -> str: ...
上层编排只依赖这个接口,不关心背后是真实模型还是测试替身。异常统一收敛为业务可识别的错误类型(如超时、限流、内容拒绝),避免底层 SDK 的异常类型泄漏到路由层。重试只对幂等且可恢复的错误生效,并且要有上限——无限重试在 Agent 场景里会把一次失败放大成一场雪崩。
/agent/chat 的处理顺序值得单独强调:
这个顺序不是随意的:护栏省钱,检索提质量,工具补事实,模型做归纳。任何一步失败,都应有明确的降级路径,而不是让整个请求 500。
/rag/ingest 的职责被刻意压到最小:接收文本、按固定窗口加重叠切块、写入存储。切块策略先用最简单的字符窗口即可,重点是接口形态稳定——后续换成更精细的语义切块时,调用方无感知。写入时保留来源标识与块序号,检索结果才能被追溯。
这是本章最容易被忽视却最影响效率的一条纪律。不要等全部写完再测试,否则错误会堆叠在一起,你无法判断是哪一层写错了。建议的节奏是:
config.py + schemas.py:跑一次配置加载与 DTO 校验的单元测试。llm_client.py + guardrails.py:用假客户端验证正常路径与拦截路径。rag_store.py + orchestrator.py:验证检索为空、工具命中、模型超时三种分支。/health 与 /agent/chat 的端到端冒烟。每轮验证都很轻,但累计起来形成了一张细密的反馈网。真实模型测试单独标记,必须显式开启,不进入默认测试集。
一个“最小模型调用”服务的价值,不在于它调用了多强的模型,而在于它把不确定性拆解成了可管理的部分:配置有默认值、接口有契约、调用有超时与降级、链路有顺序、测试有节奏。做到这些,这个 Python 服务才真正具备了被业务后端调用的资格,也才谈得上后续的扩展——加更多工具、换更强模型、接更复杂的检索,都只是在这副骨架上的增量替换,而不是推倒重来。