# Agent 底座使用文档 > 版本:v1.0 > 适用范围:底座负责人、业务 Agent 开发人员、接口联调人员 > 当前运行方式:FastAPI + MySQL + 独立 Worker + Redis/Milvus/Neo4j 可选基础设施 本文说明如何启动底座、注册业务 Agent、提交运行、读取结果,以及如何使用记忆、配置、模型路由和公共会话能力。 接口字段的最终权威定义仍是《05-接口文档.md》,数据库的最终权威定义仍是《00-新数据库基线设计.md》和《02-数据库建表设计.md》。 ## 1. 运行前提 项目固定使用 Python 3.13 环境: ```powershell conda activate jr_py313 python --version ``` 首次安装依赖: ```powershell pip install -r requirements.txt ``` 项目依赖的 `.env` 不提交到代码仓库。可以复制模板后填写本机配置: ```powershell Copy-Item .env.example .env ``` 至少需要配置: ```dotenv JWT_ISSUER=jr-local JWT_AUDIENCE=jr-agent-platform JWT_PUBLIC_KEY_PATH=config/jwt/jwt-public.pem MYSQL_DSN=mysql+asyncmy://用户名:密码@127.0.0.1:3306/jr REDIS_URL=redis://127.0.0.1:6379/0 MILVUS_URI=http://127.0.0.1:19530 NEO4J_URI=bolt://127.0.0.1:7687 ``` JWT 私钥只用于签发测试 Token,服务端只读取公钥。模型密钥通过 `secret_ref` 引用环境变量或密钥服务,不能写入 `.py`、数据库明文字段或日志。 ## 2. 数据库和迁移 迁移由 Alembic 执行,业务代码不会在运行时创建表: ```powershell alembic upgrade head python tools/audit_schema.py ``` 当前数据库包含 51 张表,其中包括: - 原有 49 张基线和已落地表; - `svc_conversation_session` 会话表; - `api_request_receipt` 公共 HTTP 写操作幂等回执表。 修改表结构前必须先对照 00 基线。允许新增表和字段,禁止重命名、删除或改变已有字段。结构指纹检查命令: ```powershell python tools/schema_fingerprint.py ``` ## 3. 启动 HTTP 服务和 Worker 需要两个终端。 终端一启动 HTTP 服务: ```powershell conda activate jr_py313 python -m uvicorn app.main:app --host 127.0.0.1 --port 8099 ``` 终端二启动运行 Worker: ```powershell conda activate jr_py313 python -m app.worker ``` 只处理一轮任务并退出: ```powershell python -m app.worker --once ``` Worker 的运行参数在 `.env` 中配置: ```dotenv WORKER_POLL_SECONDS=1 WORKER_LEASE_SECONDS=60 WORKER_RETRY_LIMIT=3 ``` HTTP 服务只负责认证、权限、参数校验和运行受理。模型调用、记忆召回、结果持久化由 Worker 执行。 ## 4. 注册业务 Agent 业务 Agent 必须继承 `BaseAgent`,只实现 `AgentDefinition` 和 `handle()`,由 `AgentFactory` 创建。 业务代码不得覆盖 `execute()`、`validate_access()`、`resolve_config()`、`recall_memory()`、`check_compliance()` 或治理绑定方法。 示例: ```python from app.core.contracts import AgentDefinition, AgentRequest, CoreResult, RequestContext from app.service.agent.base import BaseAgent class CustomerServiceAgent(BaseAgent): definition = AgentDefinition( agent_type="customer_service", version="1.0.0", allowed_roles=("customer", "operator", "admin"), allowed_portals=("api",), allowed_tools=(), supported_intents=("general",), ) async def handle( self, request: AgentRequest, context: RequestContext ) -> CoreResult: return CoreResult(text=f"已收到:{request.message}") ``` 在 `app/service/agent/bootstrap.py` 的唯一注册入口注册: ```python from app.service.agent.factory import AgentFactory def register_business_agents(factory: AgentFactory) -> None: factory.register( CustomerServiceAgent.definition, lambda context: CustomerServiceAgent(CustomerServiceAgent.definition), ) ``` 然后由 `get_agent_factory()` 在首次创建时调用注册函数。HTTP 服务和 Worker 必须共用这个注册入口,不能各自维护一份注册表。 `agent_type` 使用小写蛇形命名,例如 `customer_service`、`risk`、`advisor`。如果没有注册业务 Agent,提交该类型会返回 `404 AGENT_TYPE_NOT_FOUND`。 注册表契约测试会扫描所有已注册 Agent:构造器必须返回 `BaseAgent`,实例定义必须与注册时的 `AgentDefinition` 完全一致。业务 Agent 未通过该契约测试不得合并;工厂创建阶段也会再次拒绝 非法构造器,避免绕过公共执行链。 `get_agent_factory()` 是 HTTP 服务和 Worker 共用的底座组装入口。它会从 `model_endpoint_config` 按端点代码读取激活配置,构造 `DatabaseModelGateway → ModelGenerationService`,并注册公共只读工具 到 `ToolRegistry → ToolExecutor` 后注入工厂。业务组员只需注册自己的 Agent,不得在业务代码中重新 创建模型 Adapter、读取模型密钥或另建工具执行器。 ## 5. Agent 的公共执行顺序 每次运行固定经过: ```text 输入校验 → 角色、入口和权限校验 → 读取生效配置 → 召回当前用户记忆 → 执行业务 handle() → 超时控制 → 禁止表达、引用、敏感信息和工具记录审查 → 持久化结果、审计和 Outbox ``` 业务 Agent 可读取: - `self.config`:本次运行的不可变配置快照; - `self.memories`:当前用户的授权记忆集合; - `request`:客户端业务输入; - `context`:服务端生成的身份和权限上下文。 业务 Agent 不得直接创建 SQLAlchemy Session、Redis、Milvus 或 Neo4j Driver。关系查询必须经过 `RelationshipService`,模型调用必须经过模型路由和 `ModelGateway`。 ## 6. 提交一次 Agent 运行 ```http POST http://127.0.0.1:8099/api/v1/agent-runs Authorization: Bearer Idempotency-Key: customer-request-202609090001 Content-Type: application/json ``` 请求体: ```json { "agent_type": "customer_service", "message": "请介绍一下基金风险", "session_id": "session-uuid", "idempotency_key": "customer-request-202609090001", "metadata": { "locale": "zh-CN", "client_version": "web-1.0", "ui_entry": "customer-chat" } } ``` 返回 `202`: ```json { "run_id": "run-uuid", "trace_id": "trace-uuid", "status": "queued", "status_url": "/api/v1/agent-runs/run-uuid", "events_url": "/api/v1/agent-runs/run-uuid/events" } ``` 同一用户、同一 Agent、同一幂等键和同一正文会返回原运行;正文不同会返回 `409 IDEMPOTENCY_CONFLICT`。 ## 7. 查询和 SSE 恢复 查询运行: ```http GET /api/v1/agent-runs/{run_id} Authorization: Bearer ``` 订阅 SSE: ```http GET /api/v1/agent-runs/{run_id}/events Authorization: Bearer Accept: text/event-stream ``` 运行未完成时只收到 `start` 和心跳;最终事务提交后收到 `tools`(可选)、`delta`、`done`。已完成运行重连时使用 `replace` 返回完整正文。 这是结果级恢复:断线后重新请求同一个 `run_id` 即可恢复,不依赖 Worker 内存,也不实现事件级 `Last-Event-ID` 续传。 ## 8. 会话、取消和转人工 创建会话: ```http POST /api/v1/conversations Idempotency-Key: session-create-202609090001 ``` ```json {"agent_type": "customer_service"} ``` 结束会话: ```http POST /api/v1/conversations/{session_id}/closures Idempotency-Key: session-close-202609090001 ``` 取消运行: ```http POST /api/v1/agent-runs/{run_id}/cancellations Idempotency-Key: cancel-202609090001 ``` ```json {"reason": "user_cancelled"} ``` 转人工: ```http POST /api/v1/conversations/{session_id}/handover-requests Idempotency-Key: handover-202609090001 ``` Agent 只能提出转人工请求,不能直接分配、接单、解决或关闭客服工单。 ## 9. 记忆、关系推理和模型路由 记忆提取不提供客户端写接口。`complete_run()` 会在最终事务内写入 `memory.extraction_requested`,由 Outbox Worker 消费。 记忆查询: ```http GET /api/v1/users/me/memory-profile GET /api/v1/customers/{customer_id}/memory-profile ``` Neo4j 关系推理必须调用 `RelationshipService`,只能使用白名单关系和受限跳数;Neo4j 不可用时返回降级结果,不得绕过数据权限。 模型调用必须经过: ```text ConfigRelease → ModelRouterService → ModelGateway → 主端点/受控 fallback ``` 业务 Agent 在 `handle()` 中通过底座注入的 `generate_with_model(endpoints, prompt)` 调用模型, 不得直接导入 `httpx`、供应商 SDK 或自己读取密钥。当前已提供 OpenAI-compatible Adapter; 生产接入时由模型平台根据 `ModelEndpointConfig.base_url`、`model_name` 和 `secret_ref` 构造已批准端点,再交给 `ModelGenerationService`。没有路由端点时会失败关闭并进入 Worker 重试, 不会静默调用环境变量中的默认模型。 意图识别使用公共 `IntentClassifier`,输入为用户消息、Agent 声明的 `supported_intents` 和模型路由结果。模型只能返回严格 JSON;底座会校验意图白名单和 `confidence`(0 到 1),低于发布配置阈值时返回 `needs_clarification=true`,由业务流程澄清, 不得把低置信结果当成确定意图。格式错误、未声明意图和空输入均失败关闭。业务 Agent 不得直连 模型或自行解析供应商响应。 该分类器已经接入 `BaseAgent.execute()`:完成鉴权、配置和记忆召回后,底座会从数据库解析当前 激活模型端点并在 `handle()` 前自动分类,最终分类结果自动写入 `CoreResult.intent`。组员无需调用 `ModelRouterService`、创建 `IntentClassifier` 或向 `handle()` 传端点,也不得覆盖 `classify_intent()` 和 `bind_intent_classifier()`。 工具调用必须经过工厂注入的 `ToolExecutor`。业务 Agent 使用 `await self.call_tool(name, arguments, intent=..., context=context)`,不能直接访问数据库或外部服务。每个工具必须声明 Pydantic 输入模型、权限码、允许角色和只读属性;公共 Agent 工具拒绝写操作。执行前检查当前 意图白名单、角色、权限和参数,执行过程有超时,结果只保留脱敏摘要,并生成工具来源引用和审计记录。 投顾适当性校验必须使用公共 `SuitabilityService`(或其 `suitability_tool_handler` 工具入口), 不得在业务 Agent 中复制 C1-C5/R1-R5 匹配规则。输入包括客户风险等级、产品风险等级、专业投资者 标记、风险揭示和测评有效期;输出为不可变的 `allowed`、`reason_code`、`required_disclosure`、 `requires_confirmation`、`requires_recording`。客户风险等级低于产品、测评已过期时必须拒绝;专业 投资者也不能绕过审计。通过和拒绝决定都会写入 `interaction_audit`,服务只读,不修改交易、产品或 客户风险资料。业务 Agent 如需校验,应注册只读工具并通过 `self.call_tool(...)` 调用。 接口和日志只保存 `secret_ref`,不保存模型 API 明文密钥。 ## 10. 配置管理 管理接口位于 `/api/v1/admin/**`,需要 JWT、管理角色和对应权限。写操作必须同时提供: - `Idempotency-Key`; - 更新时的 `If-Match`; - 合法的发布状态转换。 配置发布流程: ```text draft → pending_review → approved → active ↘ rejected active → superseded / rollback release ``` 创建人不能审核自己的配置。工具白名单只能缩小代码中 `AgentDefinition.allowed_tools` 的范围,不能通过数据库配置扩大权限。 ## 11. 统一错误处理 常见错误: | HTTP | 错误码 | 含义 | |---:|---|---| | 400/422 | `VALIDATION_ERROR` | 请求字段或业务输入不合法 | | 401 | `UNAUTHORIZED` | Token 缺失、无效、过期或身份字段非法 | | 403 | `FORBIDDEN` | 角色、权限、入口或数据范围不允许 | | 404 | `AGENT_TYPE_NOT_FOUND` / `RESOURCE_NOT_FOUND` | Agent 或资源不存在/不可见 | | 409 | `IDEMPOTENCY_CONFLICT` | 同一幂等键对应不同请求 | | 503 | `RECOVERABLE_ERROR` | 可重试依赖或执行错误 | 错误响应不会返回 SQL、堆栈、模型原文、供应商响应或密钥。 ## 12. 开发完成前的验收命令 ```powershell python -m pytest -q -p no:cacheprovider python -m ruff check app tests tools alembic python -m mypy app python tools/check_authoritative_docs.py python tools/audit_schema.py ``` 新增业务 Agent 至少补充: 1. 每个支持意图的正常、低置信和异常用例; 2. 未授权角色、入口、工具和客户范围用例; 3. 配置、记忆、合规、SSE 和最终持久化回归; 4. 业务边界用例,例如 Agent 不得代客下单、审核方案或处置风险预警。 ## 13. 当前边界 本底座负责公共架构、鉴权、工厂、运行调度、持久化、记忆基础、关系服务、配置、模型路由和公共接口。 客服、投顾、风控和运营 Agent 的具体意图、提示词、工具实现和业务状态机由业务组员负责,但必须通过本文规定的工厂和公共执行流程接入。 当前系统业务交易范围是场内基金模拟交易。场外运营数据必须使用独立表和独立接口,不得写入场内交易表。 ## 14. 基金行情工具当前状态 底座已注册 `query_fund_quote` 公共只读工具,经过 `ToolRegistry`、`ToolExecutor` 和统一工厂注入。 业务 Agent 必须同时在 `AgentDefinition.allowed_tools` 和发布配置的 `agent_tools/:fund_quote` 中声明后才能使用。未注册业务 Agent 不能直接提交运行, 底座也没有开放绕过 Agent 执行链的行情 HTTP 接口。